多线程入门二
第一:线程安全问题
产生原因:多个线程同时共享,同一个全局变量或静态变量
实际案例:多线程模拟售票(线程不安全版本)
package com.zzg.concurrent;
/**
* 模拟火车售票--展示线程不安全
*
* @author Administrator
*
*/
public class Two implements Runnable {
private Integer ticket = 100;
@Override
public void run() {
// TODO Auto-generated method stub
while(ticket > 0) {
// 售票方法调用
sale();
}
}
public void sale() {
if (ticket > 0) {
try {
Thread.sleep(10);
} catch (Exception e) {
}
System.out.println(Thread.currentThread().getName() + ",出售 第" + (100 - ticket + 1) + "张票.");
ticket--;
}
}
}
package com.zzg.concurrent;
public class TwoDomain {
public static void main(String[] args) {
// TODO Auto-generated method stub
Two two = new Two();
// 共享线程two 中ticket 属性
Thread thread1 = new Thread(two);
Thread thread2 = new Thread(two);
thread1.start();
thread2.start();
}
}
效果:
Thread-1,出售 第1张票.
Thread-0,出售 第1张票.
Thread-0,出售 第3张票.
Thread-1,出售 第3张票.
Thread-0,出售 第5张票.
Thread-1,出售 第5张票.
Thread-1,出售 第7张票.
......
第二:线程安全解决办法
1问:如何解决多线程之间线程安全问题?
答:使用多线程之间同步(同步代码块、同步方法)或使用锁(lock)。
2问:为什么使用线程同步或使用锁能解决线程安全问题呢?
答:将可能会发生数据冲突问题(线程不安全问题),只能让当前一个线程进行执行。代码执行完成后释放锁,让后才能让其他线程进行执行。这样的话就可以解决线程不安全问题。
3问:什么是多线程之间同步?
答:当多个线程共享同一个资源,不会受到其他线程的干扰。
1、同步代码块:将可能会发生线程安全问题的代码,给包括起来。
语法格式:
synchronized(锁对象){
可能会发生线程冲突问题
}
/**
* 模拟火车售票--展示线程安全(同步块)
*
* @author Administrator
*
*/
public class TwoBlock implements Runnable {
private Integer ticket = 100;
// 自定义锁对象
private Object locker = new Object();
@Override
public void run() {
// TODO Auto-generated method stub
while(ticket > 0) {
// 售票方法调用
sale();
}
}
public void sale() {
synchronized(locker) {
if (ticket > 0) {
try {
Thread.sleep(10);
} catch (Exception e) {
}
System.out.println(Thread.currentThread().getName() + ",出售 第" + (100 - ticket + 1) + "张票.");
ticket--;
}
}
}
}
执行函数:
package com.zzg.concurrent;
public class TwoDomain {
public static void main(String[] args) {
// TODO Auto-generated method stub
//Two two = new Two();
TwoBlock two = new TwoBlock();
// 共享线程two 中ticket 属性
Thread thread1 = new Thread(two);
Thread thread2 = new Thread(two);
thread1.start();
thread2.start();
}
}
效果展示:
Thread-0,出售 第1张票.
Thread-0,出售 第2张票.
Thread-0,出售 第3张票.
Thread-0,出售 第4张票.
Thread-0,出售 第5张票.
Thread-0,出售 第6张票.
Thread-0,出售 第7张票.
Thread-0,出售 第8张票.
Thread-0,出售 第9张票.
Thread-0,出售 第10张票.
Thread-0,出售 第11张票.
Thread-0,出售 第12张票.
Thread-0,出售 第13张票.
Thread-0,出售 第14张票.
Thread-0,出售 第15张票.
Thread-0,出售 第16张票.
Thread-0,出售 第17张票.
Thread-0,出售 第18张票.
Thread-0,出售 第19张票.
Thread-0,出售 第20张票.
...........
2、同步函数:在方法上修饰synchronized 称为同步函数
语法格式:
public void synchronized methodName(paramter){
// 执行同步函数方法题
}
package com.zzg.concurrent;
/**
* 模拟火车售票--展示线程安全(同步函数)
*
* @author Administrator
*
*/
public class TwoFunc implements Runnable {
private Integer ticket = 100;
@Override
public void run() {
// TODO Auto-generated method stub
while(ticket > 0) {
// 售票方法调用
sale();
}
}
public synchronized void sale() {
if (ticket > 0) {
try {
Thread.sleep(10);
} catch (Exception e) {
}
System.out.println(Thread.currentThread().getName() + ",出售 第" + (100 - ticket + 1) + "张票.");
ticket--;
}
}
public static void main(String[] args) {
TwoFunc two = new TwoFunc();
// 共享线程two 中ticket 属性
Thread thread1 = new Thread(two);
Thread thread2 = new Thread(two);
thread1.start();
thread2.start();
}
}
效果展示:
Thread-0,出售 第1张票.
Thread-0,出售 第2张票.
Thread-0,出售 第3张票.
Thread-0,出售 第4张票.
Thread-0,出售 第5张票.
Thread-0,出售 第6张票.
Thread-0,出售 第7张票.
Thread-0,出售 第8张票.
Thread-0,出售 第9张票.
Thread-0,出售 第10张票.
Thread-0,出售 第11张票.
Thread-0,出售 第12张票.
Thread-0,出售 第13张票.
Thread-0,出售 第14张票.
Thread-0,出售 第15张票.
Thread-0,出售 第16张票.
Thread-0,出售 第17张票.
Thread-0,出售 第18张票.
Thread-0,出售 第19张票.
Thread-0,出售 第20张票.
...........
同步代码块与同步函数之间的锁区别:
同步代码块锁:自定义锁对象
同步函数锁:this 锁对象
3、静态同步函数
特点如下:
方法上加上static关键字,使用synchronized 关键字修饰 或者使用类.class文件。
静态的同步函数使用的锁是 该函数所属字节码文件对象
package com.zzg.concurrent;
/**
* 模拟火车售票--展示线程安全(静态同步函数)
*
* @author Administrator
*
*/
public class TwoStatic implements Runnable {
private static Integer ticket = 100;
@Override
public void run() {
// TODO Auto-generated method stub
while (ticket > 0) {
// 售票方法调用
sale();
}
}
public static void sale() {
synchronized (TwoStatic.class) {
if (ticket > 0) {
try {
Thread.sleep(10);
} catch (Exception e) {
}
System.out.println(Thread.currentThread().getName() + ",出售 第" + (100 - ticket + 1) + "张票.");
ticket--;
}
}
}
public static void main(String[] args) {
TwoStatic two = new TwoStatic();
// 共享线程two 中ticket 属性
Thread thread1 = new Thread(two);
Thread thread2 = new Thread(two);
thread1.start();
thread2.start();
}
}
效果展示:
Thread-0,出售 第1张票.
Thread-0,出售 第2张票.
Thread-0,出售 第3张票.
Thread-0,出售 第4张票.
Thread-0,出售 第5张票.
Thread-0,出售 第6张票.
Thread-0,出售 第7张票.
Thread-0,出售 第8张票.
Thread-0,出售 第9张票.
Thread-0,出售 第10张票.
Thread-0,出售 第11张票.
Thread-0,出售 第12张票.
Thread-0,出售 第13张票.
Thread-0,出售 第14张票.
Thread-0,出售 第15张票.
Thread-0,出售 第16张票.
Thread-0,出售 第17张票.
Thread-0,出售 第18张票.
Thread-0,出售 第19张票.
Thread-0,出售 第20张票.
...........
synchronized 总结:
synchronized 修饰方法使用锁是当前this锁。
synchronized 修饰静态方法使用锁是当前类的字节码文件
1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。