美文网首页线程
java并发编程(2)线程常用方法

java并发编程(2)线程常用方法

作者: monkey01 | 来源:发表于2017-09-12 16:42 被阅读23次

本篇是系列第二篇,主要介绍下java中线程操作常用的函数和隔离区数据保护方法,join()、wait()、notify()、synchronized、volatile。

1.join()

当使用join的时候,表示该线程插入,当前线程等待该线程执行完毕
当线程执行完毕后,被等待的线程会在退出前调用notifyAll通知所有等待线程继续执行。下面我们做个实验来看下join的具体效果,这样比较好理解。

public class JoinThreadMain {
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(new TestThread());
        thread1.start();

        System.out.println("count = " + count);

    }

    private static int count = 0;

    public static class TestThread implements Runnable{
        @Override
        public void run() {
            for(int i=0; i<10000; i++){
                count++;
            }
        }
    }
}

从代码看定义了一个static的count变量用于计数,在main函数主线程中调用线程start方法后,接着输出count值,因为start后线程,主线程会直接输出当前的count值,当前count值可能还未执行完线程的循环,所以输出的值一般都是小于10000的,例如下面之行后输出的是63。

count = 63

如果我们要实现子线程完成后再其他线程再输出,就可以使用join方法将该线程临时插入当前线程去执行,直到执行完毕再继续执行当前线程,修改后的代码如下:

public class JoinThreadMain {
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(new TestThread());
        thread1.start();
        thread1.join();
        System.out.println("count = " + count);

    }

    private static int count = 0;

    public static class TestThread implements Runnable{
        @Override
        public void run() {
            for(int i=0; i<10000; i++){
                count++;
            }
        }
    }
}

现在的输出结果就是我们期望的10000了。

count = 10000

2.wait()、notify()

jdk中两个非常重要的接口线程方法,wait和notity,这两个方法不在Thread类而是在Object类。当一个对象实例调用wait方法后,当前线程就会在这个对象上等待,当thread1调用了obj.wait(),那么thread1就会进入等待队列,当obj.notify被调用,系统会从队列中随机选择一个线程继续执行。obj.wait方法不可以随便调用必须包含在对应的synchronzied语句中,无论是wait还是notify都需要先获得目标对象的监视器。

public class WaitNotifyMain {
    private final static Object object = new Object();

    public static void main(String[] args) throws InterruptedException {
        
        Thread thread1 = new Thread(new Thread1());
        Thread thread2 = new Thread(new Thread2());
        thread1.start();
        thread2.start();

    }

    public static class Thread1 extends Thread {
        public void run() {
            synchronized (object) {
                System.out.println(System.currentTimeMillis() + ":thread1 start !");
                try {
                    System.out.println(System.currentTimeMillis() + ":thread1 wait for object !");
                    object.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(System.currentTimeMillis() + ":thread1 end!");
            }
        }
    }

    public static class Thread2 extends Thread {
        public void run() {
            synchronized (object) {
                System.out.println(System.currentTimeMillis() + ":thread2 start ! notify one thread");
                object.notify();

                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(System.currentTimeMillis() + ":thread2 end!");
            }
        }
    }
}

3.synchronized

synchronized是最常用的隔离区保护的关键字,线程中方法如果使用synchronized则表示该方法同时只能有一个线程访问,这就能够保证隔离区数据的线程安全,这也是保证隔离区数据安全最常用的方法,下面定义的add方法不管并发多大计算的结果都不会改变。

public class SyncThread implements Runnable {
    private synchronized void add(){
        SynchronizedMain.count2++;
    }

    @Override
    public void run() {
        for(int i=0; i<100000; i++){
            add();
        }
    }
}

4.Volatile

当用volatile去申明变量时,就等于告诉虚拟机,这个变量极有可能会被某些程序或者线程修改,当值修改,所有线程都能看到该值变化。但是执行会发现count还是不等于100000,因为当有线程并发操作count的时候,虽然count修改后通知到各个线程,但是并发读取到值的线程还是会存在修改后覆盖的情况,所以肯定是小于100000,所以volatile不适合用在大并发的场景。

public class VolatileMain {
    
    static volatile int count = 0;

    public static void main(String[] args) throws InterruptedException {
        Thread[] threads = new Thread[10];
        for(int i=0; i<10; i++){
            threads[i] = new Thread(new MyVolatileThread());
            threads[i].start();
        }

        for(int i=0; i<10; i++){
            threads[i].join();
        }
        
        System.out.println(count);
    }

    public static class MyVolatileThread implements Runnable{
        @Override
        public void run() {
            for(int i=0; i<10000; i++){
                count++;
            }
        }
    }

}

相关文章

网友评论

    本文标题:java并发编程(2)线程常用方法

    本文链接:https://www.haomeiwen.com/subject/idncsxtx.html