zoukankan      html  css  js  c++  java
  • java线程基础知识----线程与锁

      我们上一章已经谈到java线程的基础知识,我们学习了Thread的基础知识,今天我们开始学习java线程和锁。

      1.  首先我们应该了解一下Object类的一些性质以其方法,首先我们知道Object类的是java的顶层类,所有的类都集成自Object类,包括string和数组。而且每一个Object都有一个锁,同一时间只能有一个线程暂用这个对象的锁。这是我们今天学习的前提条件,至于Object的一些方法我们在后面的章节中会进行学习。

      2.  java锁之synchronized: 想必大家都知道java的synchronized关键字,在我看来这是锁操作中相对简单的方法,但是对事物我总有一个定义“简单的就是可扩展性差的”,下面我们将了解synchronized关键字的用法:

    A. 入门基础实例: 举一个经典的售票例子,就是同时有2个窗口售票(当然是电子票),而且票的数量是一定的,假设20张。两个窗口之间售票相互独立。我们应该怎么实现?

    public class ThreadTest {
        public static void main(String[] args) throws InterruptedException{
            Thread1 thread1 = new Thread1();
            Thread threadA = new Thread(thread1);
            Thread threadB = new Thread(thread1);
            threadA.start();
            threadB.start();
        }
    }
    class Thread1 implements Runnable{
        private Integer ticket = 100;
        public void run(){
                while ((ticket--) >0) {
                    System.out.println("窗口"+Thread.currentThread().getName()+"卖票,当前票的数量为"+ticket);
                }
        }
    }
    计算结果: 具有随机性和不唯一性

      显然这样的结果并不是我们想要的,这里我们先分析一下原因,为什么会导致这种计算结果?在访问临界区资源的时候我们并没有控制进入临界区的线程数量,也就是说我们在这个过程中可能有两个线程同时进入了这段"临界区",访问了"临界资源"。假设有两个线程同时访问到了ticket值为100,但是两个线程都进行了--操作,导致本来线程应该为98的,但是实际结果确实99。这其实就是线程不安全的。

      那么我们如何更改上面的程序进行更改呢?我们只需要引入synchronized关键字,首先我们说一下synchronized方法的两种使用方式:

        一: synchronized代码块:如上面的程序只需要进行如下更改即可:

    public class ThreadTest {
        public static void main(String[] args) throws InterruptedException{
            Thread1 thread1 = new Thread1();
            Thread threadA = new Thread(thread1);
            Thread threadB = new Thread(thread1);
            threadA.start();
            threadB.start();
        }
    }
    class Thread1 implements Runnable{
        private Integer ticket = 100;
        public void run(){
            synchronized (ticket) {
                while ((ticket--) >0) {
                    System.out.println("窗口"+Thread.currentThread().getName()+"卖票,当前票的数量为"+ticket);
                }
            }
        }
    }
    计算结果:  这样就能够按照我们预定的顺序进行程序输出了。

    但是我们需要注意以下问题:  第一:我们设置了synchronized代码块,那么想要访问这段代码块的线程就会被阻塞。

      第二: 同样我们应该注意一个问题,我们获取到的锁是对象锁,那么如果在Thread类中存在多个synchronized方法,并且我们获取的对象的锁就是Thread类,那么只要有一个线程获取到了对象锁,那么另外的synchronized方法讲会被阻塞。

    二: synchronized方法:  与上面类似,语法如下: public void synchronized test();

     3. Object类中与线程锁相关的方法:

    A.  wait方法: 首先我们知道wait方法使当前线程释放对象锁,让其他线程可以获取对象锁进入同步代码块。并且将当前线程放入到对象等待池。

    B.       notify与notifyAll方法: 在当前线程中调用notify方法,则可以唤醒等待对象锁的线程执行。但是需要注意一点,如果对象等待池中存在很多线程,我们调用notifyAll方法的话,选择线程是随机的。

      我们在使用的时候还应该注意一个问题,使用这些方法都必须在获取对象锁的代码块或者方法中使用。

      综合例子:

    public class ThreadTest {
        public static Integer temp = 0;
        public static void main(String[] args) throws InterruptedException{
            ThreadA threadA = new ThreadA();
            ThreadB threadB =new ThreadB();
            threadA.start();
            threadB.start();
        }
    }
    class ThreadA extends Thread{
        public void run() {
            synchronized (ThreadTest.temp) {
                for(int i=0;i<5;i++){
                    System.out.println(Thread.currentThread().getName()+"输出"+i);
                    if(i== 3)
                        try {
                            System.out.println("线程调用wait方法");
                            ThreadTest.temp.wait();
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                }
            }
        }
    }
    class ThreadB extends Thread{
        public void run() {
            synchronized (ThreadTest.temp) {
                for(int i = 0;i<5;i++){
                    System.out.println(Thread.currentThread().getName()+"输出"+i);
                    if(i==4){
                        System.out.println(Thread.currentThread().getName()+"结束");
                        System.out.println("线程调用notify方法");
                        ThreadTest.temp.notify();
                    }
                }
            }
        }
    }
    输出结果:

    Thread-0输出0
    Thread-0输出1
    Thread-0输出2
    Thread-0输出3
    线程调用wait方法
    Thread-1输出0
    Thread-1输出1
    Thread-1输出2
    Thread-1输出3
    Thread-1输出4
    Thread-1结束
    线程调用notify方法
    Thread-0输出4

      

  • 相关阅读:
    Regexp
    Qt Customize QVariant
    Paradox
    Write File
    Division of Line Segment
    How to Get Vertical Line from Point and Line
    IOPS-百度百科
    磁盘的读写-想起了SGA PGA DBWR LGWR...
    记一次备份发起时间延后问题
    V$RMAN_BACKUP_JOB_DETAILS
  • 原文地址:https://www.cnblogs.com/liboBlog/p/6443302.html
Copyright © 2011-2022 走看看