您的位置:首页 > 编程语言 > Java开发

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

2017-05-11 16:46 417 查看
关于多线程同步,拿一个比较经典的题目来说,卖火车票,假设有3个线程,代表3个售票窗口

一共是100张火车票,由三个窗口共同售卖,那么这100张票就是三个线程的共享数据,因为

每一张票都有唯一性,同一张票只能由一个售票窗口售出,那么就需要要求给线程加同步机制

搜集了一些资料,针对共享数据的同步,目前我总结了3种方法:

synchronized锁住线程内的共享变量

volatile标识共享变量

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 {

4000
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