目录
1. 线程同步介绍
2. 互斥锁机制
3. 利用synchronized 关键字实现同步 *** 作
1)同步代码块
实例代码
2)同步方法
实例代码
4. 对synchronized的进一步说明
5. Lock接口(java.util.concurrent.locks)实现线程同步(手动加解锁)
实例代码
6. 线程的死锁
1. 线程同步介绍
在并发程序设计中,对多线程共享的资源或数据称为临界资源或同步资源,而把每个线程中访问临界资源的那一段代码称为临界代码或临界区。临界区必须互斥地使用,为了使临界代码对临界资源的访问成为一个不可被中断的原子 *** 作,Java技术利用对象“互斥锁”机制来实现线程间的互斥 *** 作。
2. 互斥锁机制在Java中每个对象都有一个“互斥锁”与之相连。当线程A获得了一个对象的互斥锁后,线程B若也想获得该对象的互斥锁,就必须等待线程A完成规定的 *** 作并释放出互斥锁后才能获得并执行相关的 *** 作。
3. 利用synchronized 关键字实现同步 *** 作 1)同步代码块synchronized(对象) {
临界代码段
}
对象是多个线程共同 *** 作的公共变量,即需要锁定的临界资源,它将被互斥地使用(常为this、静态Object对象)
实例代码package Learning; public class $3_synchronized { public static void main(String[] args) { window winds = new window(); Thread t1 = new Thread(winds, "窗口1"); Thread t2 = new Thread(winds, "窗口2"); Thread t3 = new Thread(winds, "窗口3"); //利用同一继承Runnable接口类的对象构建多个线程,实现线程间的数据共享,利用同步代码块实现互斥 t1.start(); t2.start(); t3.start(); } } class window implements Runnable { private int tickets = 30; @Override public void run() { while (true) { synchronized (this) { if(tickets>0){ System.out.println(Thread.currentThread().getName() + "售出了" + tickets + "号票"); tickets--; } else break; } //利用synchronized关键词使同步代码块互斥的使用 try { Thread.sleep(50); //使用sleep函数,使线程阻塞便于演示 } catch (InterruptedException e) { e.printStackTrace(); } } } }
package Learning; public class $4_synchronized { public static void main(String[] args) { window_t w1=new window_t("窗口1"); window_t w2=new window_t("窗口2"); window_t w3=new window_t("窗口3"); w1.start(); w2.start(); w3.start(); } } class window_t extends Thread{ private static int tickets=30; //将tickets设置为静态变量来实现线程间数据共享 private static final Object obj=new Object(); //使用this仍无法实现互斥效果,因为不是同一个线程对象;故创建静态的Object对象使用 public window_t(String t){ this.setName(t); } public void run(){ while(true) { synchronized (obj) { //此处也可以使用window_t.class反射类(类也是对象?) if (tickets > 0) { System.out.println(getName() + "售出了" + tickets + "号票"); tickets--; } else break; } try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } }2)同步方法
public synchronized 返回类型 方法名() {
方法体
}(常使用static方法解决继承Thread类的线程安全问题)
实例代码package Learning; public class $5_synchronized { public static void main(String[] args) { window_r winds=new window_r(); Thread t1 = new Thread(winds, "窗口1"); Thread t2 = new Thread(winds, "窗口2"); Thread t3 = new Thread(winds, "窗口3"); t1.start(); t2.start(); t3.start(); } } class window_r implements Runnable { private int tickets = 30; @Override public void run() { while (sell()) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } private synchronized boolean sell() { if (tickets > 0) { System.out.println(Thread.currentThread().getName() + "卖出了" + tickets + "号票"); tickets--; return true; } else return false; } //synchronized方法,方法会被互斥执行 }
注意:当被synchronized限定的代码段执行完,就自动释放互斥锁。
4. 对synchronized的进一步说明(1)由于所有锁定同一个临界代码的线程之间在synchronized代码块上是互斥的,这些线程的synchronized代码块之间是串行执行的,不再是互相交替穿插并发执行,因而保证了synchronized代码块 *** 作的原子性
(2)synchronized代码块中的代码数量应只包含必要部分,否则会失去多线程并发执行的很多优势,但应该保证所有对临界代码中共享变量的访问与 *** 作均在synchronized代码块中进行。
(3)临界代码中的共享变量应定义为private型。否则,其他类的方法可能直接访问和 *** 作该共享变量,这样synchronized的保护就失去了意义
(4)对于static方法,要么整个方法是synchronized,要么不是
5. Lock接口(java.util.concurrent.locks)实现线程同步(手动加解锁)ReentrantLock类:实现了Lock接口,可以利用其对象调用lock()、unlock()方法实现手动加解锁
优先使用顺序:Lock(更为灵活) > 同步代码块 > 同步代码块
实例代码package Learning; import java.util.concurrent.locks.ReentrantLock; public class $6_Lock { public static void main(String[] args) { window_l wins=new window_l(); Thread t1=new Thread(wins,"窗口1"); Thread t2=new Thread(wins,"窗口2"); Thread t3=new Thread(wins,"窗口3"); t1.start(); t2.start(); t3.start(); } } class window_l implements Runnable{ private static int tickets=30; private final ReentrantLock lock=new ReentrantLock(); @Override public void run() { while(true){ try { lock.lock(); //加锁 if(tickets>0){ System.out.println(Thread.currentThread().getName()+"卖出了"+tickets+"号票"); tickets--; } else break; } finally { //加上finally,否则break后未解锁无法继续运行 lock.unlock(); //解锁 } try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } }6. 线程的死锁
两个或多个线程相互等待导致都不能执行;产生的条件为:
(1)互斥条件
(2) 请求和保持条件
(3) 不剥夺条件
(4) 环路等待条件
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)