java 线程同步
来源:互联网 发布:神武2mac版能玩吗 编辑:程序博客网 时间:2024/06/07 11:06
这个问题是我最近在做实习笔试的时候遇到的,当时很水的 用了同步块搞定了,不过现在还是决定稍微深入一点。
总的来说线程同步就是通过加锁和解锁机制来实现的,如果存在2个线程对同一个变量的访问,特别是出现删改的操作,这时候就必须对变量进行加锁,限制并发访问的线程数量。我对这个概念的了解始于操作系统,我记得这里面存在一个临界区的概念。临界区是涉及到线程共享资源操作的区域的总体,对于共享资源的操作需要以串行形式存在,当然为了访问性能,读操作可以多线程,但是读写必须分离,简单说就是同一个时刻只能有至多一个线程来操作临界区中线程的共享资源。
之前在C#中实现过线程同步,java中的线程同步好像没有那么好用,(ps 基于我目前接触到的方面)。
首先一个最粗暴的方式就是直接同步关键字
给方法加上synchronized, 这样同一个对象的该方法同时只有一个线程能调用,这个算是最简单粗暴的吧。
然后到了同步代码块
public class Main {Object metrux;int applecount;public Main() {metrux = new Object();applecount = 0;}public static void main(String[] args) {// TODO Auto-generated method stubMain main = new Main();main.startThread();}public void startThread() {PutApple putApple = new PutApple();GetApple getApple = new GetApple();Thread putThread = new Thread(putApple);Thread getThread = new Thread(getApple);putApple.start();getApple.start();}class PutApple extends Thread {public void run() {//boolean isFull = false;while (true) {synchronized (metrux) {if (applecount < 5) {applecount++;System.out.println("Put a apple.now have " + applecount+ " apple(s)");if(applecount == 1){metrux.notify();}} else {//isFull = true;System.out.println("Package full"); try {metrux.wait();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}//if(isFull){//Thread.yield();//}try {Thread.sleep(100);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}class GetApple extends Thread {public void run() {//boolean isEmpty =false;while (true) {synchronized (metrux) {if (applecount > 0) {applecount--;System.out.println("Get a apple.now have " + applecount+ " apple(s)");if(applecount == 4){metrux.notify();}} else {//isEmpty = true;System.out.println("Package Empty");try {metrux.wait();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}try {Thread.sleep(300);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}//if(isEmpty){//Thread.yield();//}}}}}
上面的 extends Thread 可以无视 没有用的, 同步代码块是用synchronized (object){} 的结构对代码区进行加锁,因为java中每个对象都有一个对象锁,这个语句就是请求对象的对象锁,同时只能有一个代码块能获得这个锁,这样也就保证了临界区访问的正确性。
在代码中我尝试了 wait 和notify的方法, wait方法是让线程退出同步块 同时释放锁,并且在被唤醒之前 不去获得新的该对象的锁,
notify 方法是让线程退出同步块,同时释放锁,并且随机唤醒一个在这个对象上等待的线程
基于这样的原则 我们可以做到类似循环打印的事情。
package concurrent;//会出现死锁 在多核情况下 不稳定public class PrintABC implements Runnable {private String name;private Object prev;private Object self;private PrintABC(String name, Object prev, Object self) {this.name = name;this.prev = prev;this.self = self;}@Overridepublic void run() {int count = 10;while (count > 0) {synchronized (prev) {synchronized (self) {System.out.print(name);count--;self.notify();}try {prev.wait();} catch (InterruptedException e) {e.printStackTrace();}}}}public static void main(String[] args) throws Exception {Object a = new Object();Object b = new Object();Object c = new Object();PrintABC pa = new PrintABC("A", c, a);PrintABC pb = new PrintABC("B", a, b);PrintABC pc = new PrintABC("C", b, c);new Thread(pa).start();Thread.sleep(1);new Thread(pb).start();Thread.sleep(1);new Thread(pc).start();Thread.sleep(1);}}在我们预期的情况下 我们会认为打印出ABCABC。。。。这样的结构,但是这个在多核的情况下实际上时不稳定的,任何顺序都可能出现,同时存在一个问题,比如 A线程开始,拿到C锁,之后主线程开启B线程,B线程拿到A锁,主线程开启C线程,C线程拿到A锁,这样的情况下就会出现死锁,虽然几率小,但是问题还是存在。
这时候最后就要引入信号量这个类,目前我还没有深入了解,我目前就当成了PV操作里的锁机制,以及C#中的同步锁。Semaphore这个类,可以实现获得锁,释放锁的操作,并且可以控制获得锁的对象的个数,这个在很多情况下有很大价值,现在就放一个用信号量改进的循环打印ABC的多线程同步demo
package concurrent;import java.util.concurrent.Semaphore;public class TestSemaphore {Semaphore semaphoreA = new Semaphore(1);Semaphore semaphoreB = new Semaphore(1);Semaphore semaphoreC = new Semaphore(1);public static void main(String[] args) {TestSemaphore testSemaphore = new TestSemaphore();testSemaphore.test();} public void test() {try {semaphoreB.acquire();semaphoreC.acquire();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}Thread printA = new Thread(new Print("A", semaphoreA, semaphoreB));Thread printB = new Thread(new Print("B", semaphoreB, semaphoreC));Thread printC = new Thread(new Print("C", semaphoreC, semaphoreA));printA.start();printB.start();printC.start();}class Print implements Runnable {String name;Semaphore mutex;Semaphore mutexnext;public Print(String name, Semaphore mutex, Semaphore mutexnext) {this.name = name;this.mutex = mutex;this.mutexnext = mutexnext;}public void run() {int i = 10;while (i-- > 0) {try {mutex.acquire();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println("this is : " + name);mutexnext.release();}}}}
我目前的了解就到这里,欢迎大神带来意见和新的方法途径。
- JAVA线程-JAVA同步
- Java线程:线程的同步-同步方法
- Java线程:线程的同步-同步块
- Java线程:线程的同步-同步方法
- Java线程:线程的同步-同步块
- Java线程:线程的同步-同步方法
- Java线程:线程的同步-同步方法
- Java线程:线程的同步-同步块
- Java线程:线程的同步-同步方法
- Java线程:线程的同步-同步块
- Java线程:线程的同步-同步方法
- Java线程:线程的同步-同步块
- Java线程:线程的同步-同步方法
- Java线程:线程的同步-同步块
- Java线程:线程的同步-同步方法
- Java线程:线程的同步-同步块
- Java线程:线程的同步-同步方法
- Java线程:线程的同步-同步方法
- VC++文件操作
- Gray Code
- 在os x系统上搭建php + apache +mysql的一点小体会
- 类似购物车小红点的实现-BadgeView使用
- Deprecated: mysql_connect(): The mysql extension is deprecated and will be removed in the future: us
- java 线程同步
- jquery验证规则
- Suricata规则编写——HTTP关键字
- android学习一点day01
- Android-->Launcher拖拽事件详解【androidICS4.0--Launcher系列二】
- Abstract class and Interface
- Linux下无线上网
- vbox ubuntu adtbundle 手机调试
- C01函数