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

关于多线程同步,拿一个比较经典的题目来说,卖火车票,假设有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++;
        }
    }
}

你可能感兴趣的:(java,多线程)