- 同步线程
为解决多线程争用统一资源的争用问题,我们常用synchronized关键字修饰的方法来解决。 由于java的每个对象都有一个内置锁,当用此关键字修饰方法时, 内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。synchronized关键字也可以修饰静态方法,此时如果调用该静态方法,将会锁住整个类。 - 同步是多线程中的重要概念。同步的使用可以保证在多线程运行的环境中,程序不会产生设计之外的错误结果。同步的实现方式有两种,同步方法和同步块,这两种方式都要用到synchronized关键字。
- 同步方法:
(1)同步块
代码实现:
package edu.xalead;
public class 吃包子 extends Thread {
private 包子类 p = null;
private String name = null;
public 吃包子(包子类 p,String name){
this.p = p;
this.name = name;
}
// public synchronized void eat(){
// //if (this.p.pack <= 0) break;
// // synchronized (p) {
// System.out.println(this.name + "吃第" + this.p.pack + "个包子");
// this.p.pack--;
//
// }
public void run(){
try {
while(true) {
// synchronized (p) { // 同步监视器 同步块 加锁计数器为0,线程可执行对象,为1,堵塞,不能执行
// p : 多个线程共同访问的同一个对象
// if (this.p.pack <= 0) break;
// System.out.println(this.name + "吃第" + this.p.pack + "个包子");
// this.p.pack--;
// Thread.sleep(10);
// 控制当前线程类休息
// if (this.p.pack <= 0) break;
//---
if(p.eat(this.name)) break;
Thread.sleep(10);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
/**
* 多线程的争用问题:
* 会出现两个线程共享一个对象时,一线程封装完,但没执行this.p.pack--;
* 导致另一线程到了分时执行时重复执行,但实际上,一对象只能使用或调用一次
* 解决该问题的思想:加锁,一线程使用一对象完成后,再进行另一线程的具体操作。
*/
(2) 同步方法
代码实现:
package edu.xalead;
public class 包子类 extends edu.xalead.comunication.包子类 {
/**
* 同步方法监视的对象是this.
*/
public int pack = 100;
//public 吃包子 a = null; 关联
//同步方法
public synchronized boolean eat(String name) {
if (this.pack <= 0) return true;
System.out.println(name + "吃第" + this.pack + "个包子");
//this.pack--;
--this.pack;
return false;
}
}
- 代码测试:
package edu.xalead;
public class Test { // 线程的争用
public static void main(String[] args) {
包子类 p = new 包子类();
吃包子 q = new 吃包子(p,"vbrwa");
q.start();
吃包子 q2 = new 吃包子(p,"Danny");
q2.start();
}
}
- 运行结果:
- 线程写作的实例化及实现:
package edu.xalead.comunication;
import edu.xalead.comunication.做包子;
public class 做包子 extends Thread{
private 包子类 p = null;
private String name = null;
public 做包子(包子类 p, String name){
this.p = p;
this.name = name;
}
public void run(){
try {
while(true) {
synchronized (p) {
if (p.pack <= 0) {
p.pack = 100;
System.out.println(this.name + "做好了" + p.pack + "个包子");
} else {
p.notifyAll(); // 唤醒线程
//p.notify();
p.wait(); //释放锁 释放时间
}
}
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package edu.xalead.comunication;
public class 包子类 {
public int pack = 1000;
}
package edu.xalead.comunication;
public class 吃包子 extends Thread {
private 包子类 p = null;
private String name = null;
public 吃包子(包子类 p, String name) {
this.p = p;
this.name = name;
}
public void run() {
// long start = System.currentTimeMillis();
try {
// for(int i =0;i<10000000;i++)/*while (true)*/ {
synchronized (p) {
//p : 多个线程共同访问的同一个对象
if (this.p.pack <= 0) {
//p.notifyAll();
p.wait(); //监视对象释放锁,线程数改为0
p.notify(); //唤醒做包子的
}else{
System.out.println(this.name + "吃第" + this.p.pack + "个包子");
this.p.pack--;
}
}
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
代码测试:
package edu.xalead.comunication;
import edu.xalead.包子类;
import edu.xalead.吃包子;
public class Test { // 线程的征用
public static void main(String[] args) {
包子类 p = new 包子类();
做包子 mr = new 做包子(p,"王大厨");
吃包子 q = new 吃包子(p,"vbrwa");
吃包子 q2 = new 吃包子(p,"Danny");
q.start();
q2.start();
mr.start();
}
}
运行结果:
p.wait(); 释放锁,线程数改为0; p.notify(); 唤醒(做包子的)对象。
线程之间的协作可以大大减少线程等待的时间,提高了效率。