java多线程同步机制的实现方式总结

来源:互联网 发布:ubuntu教程 百度云 编辑:程序博客网 时间:2024/06/01 09:37

关于多线程同步,拿一个比较经典的题目来说,卖火车票,假设有3个线程,代表3个售票窗口
一共是100张火车票,由三个窗口共同售卖,那么这100张票就是三个线程的共享数据,因为
每一张票都有唯一性,同一张票只能由一个售票窗口售出,那么就需要要求给线程加同步机制
搜集了一些资料,针对共享数据的同步,目前我总结了3种方法:

  1. synchronized锁住线程内的共享变量
  2. volatile标识共享变量
  3. Lock lock = new ReentrantLock();通过重入锁的方式

对比来看,1是利用了synchronized的锁机制,同一时刻,只有持有锁的线程有机会修改数据,修改完即释放锁,方案2虽然不是锁的机制,但是从感觉上来说和锁定共享变量实质一样,只是事实上是告诉jvm此变量在寄存器内的值不可信,应该去主内存去查找,也就是要重新计算.方案3是jdk5.0引入的,位于java.util.concurrent.locks中的一个可重入锁类。在高竞争条件下有更好的性能,且可以中断。深入剖析ReentrantLock的源码有助于我
们了解线程调度,锁实现,中断,信号触发等底层机制,实现更好的并发程序。

这里我在AS里通过代码实际测试了一下,1.2的效率是差不多的,3的效率明显比12的效率高

代码简单,就全部贴出来了(join方法实现的同步其实和本例子无关,但也是一种同步的场景,就是一个线程等待另一个线程的结果):

package com.practice.dev.mythread;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class MainActivity extends AppCompatActivity {    private Runnable runnable1;    private MyRunnable2 runnable2;    private MyRunnable3 runnable3;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        runnable1 = new MyRunnable();        runnable2 = new MyRunnable2();        runnable3 = new MyRunnable3();        carry1();//runnable实现的多线程同步,通过synchronized锁定共享数据,单个线程执行完便释放锁,效率一般       // carry2();//通过volatile实现的多线程同步,此关键字只能修饰变量,不能修饰类和方法,效率一般       // carry3();//通过重入锁的方式实现线程同步,此方式线程执行效率较高,几乎是同时执行,但数据也实现了同步操作       // joinCarry();//join方法确保当前线程执行过程中所持有的变量只能被自己拥有,同时有阻塞的感觉,只有当前线程结束才会向下执行    }    private void carry3() {        new Thread(runnable3).start();        new Thread(runnable3).start();        new Thread(runnable3).start();    }    private void carry2() {        new Thread(runnable2).start();        new Thread(runnable2).start();        new Thread(runnable2).start();    }    private void carry1() {        new Thread(runnable1).start();        new Thread(runnable1).start();        new Thread(runnable1).start();    }    /**     *   a.volatile关键字为域变量的访问提供了一种免锁机制,     *   b.使用volatile修饰域相当于告诉虚拟机该域可能会被其他线程更新,     *   c.因此每次使用该域就要重新计算,而不是使用寄存器中的值     *   d.volatile不会提供任何原子操作,它也不能用来修饰final类型的变量     */    class MyRunnable implements Runnable{        private volatile int ticket = 100;//不用锁,只需要volatile即可,与synchronized区别是volatile只能修饰变量,不能修饰方法和类        @Override        public void run() {            try {                while (ticket>0){                      Log.d("ticket",Thread.currentThread().getName()+"当前卖第"+ticket+"张");                      ticket--;                    Thread.sleep(500);                }            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }    class MyRunnable2 implements Runnable{        private int ticket = 100;        @Override        public void run() {            try {                while (ticket>0){                    synchronized (MyRunnable.class){                        Log.d("ticket",Thread.currentThread().getName()+"当前卖第"+ticket+"张");                        ticket--;                    }                    Thread.sleep(500);                }            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }    /**     * 重入锁的方式实现同步,此场景功能类似volatile,但是效率比voLatile高     */    class MyRunnable3 implements Runnable{        private int ticket = 100;        private Lock lock = new ReentrantLock();        @Override        public void run() {            try {                while (ticket>0){                    lock.lock();                    Log.d("ticket",Thread.currentThread().getName()+"当前卖第"+ticket+"张");                    ticket--;                    lock.unlock();                    Thread.sleep(500);                }            } catch (InterruptedException e) {                e.printStackTrace();            }finally {            }        }    }    private int a;    private void joinCarry() {        Runnable r = new ThreadTest();        Thread t1 = new Thread(r);        t1.start();        try {            t1.join();        } catch (InterruptedException e) {            e.printStackTrace();        }        Log.d("ticket",a+"");    }    class ThreadTest implements Runnable{        @Override        public void run() {            for (int i = 0; i < 5; i++) {                inc();                try {                    Thread.sleep(5000);                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }        private synchronized void inc() {            a++;        }    }}
0 0
原创粉丝点击