Java线程的同步,处理线程安全问题简讲
一、出现线程安全问题
public class WindowTest1 {
public static void main(String[] args) {
Window1 w1 = new Window1();
Thread t1 = new Thread(w1);
Thread t2 = new Thread(w1);
Thread t3 = new Thread(w1);
t1.setName("窗口一");
t2.setName("窗口二");
t3.setName("窗口三");
t1.start();
t2.start();
t3.start();
}
}
class Window1 implements Runnable{
private int ticket = 166;
@Override
public void run() {
while (true){
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":卖票, 票号为:" + ticket);
ticket--;
} else {
break;
}
}
}
}
上面会出现什么问题呢?
一:
二:
当某个线程操作未完成时,其他线程也参与进来,造成线程的安全问题
二、解决线程安全问题
解决方法: 1.同步代码块
1.1同步Runnable接口
//1.1
public class WindowTest1 {
public static void main(String[] args) {
Window1 w1 = new Window1();
Thread t1 = new Thread(w1);
Thread t2 = new Thread(w1);
Thread t3 = new Thread(w1);
t1.setName("窗口一");
t2.setName("窗口二");
t3.setName("窗口三");
t1.start();
t2.start();
t3.start();
}
}
class Window1 implements Runnable{
private int ticket = 166;
Object obj = new Object();//创建类,标识1
@Override
public void run() {
//Object obj = new Object();如果标识1在此操作是错误的,得共用锁obj,
while (true){
synchronized(this) {//考虑this是否是同个对象
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":卖票, 票号为:" + ticket);
ticket--;
} else {
break;
}
}
}
}
}
1.2同步继承Thread类
//1.2
public class WindowTest1 {
public static void main(String[] args) {
Window1 w1 = new Window1();
Window1 w2 = new Window1();
Window1 w3 = new Window1();
w1.setName("窗口一");
w2.setName("窗口二");
w3.setName("窗口三");
w1.start();
w2.start();
w3.start();
}
}
class Window1 extends Thread {
private int ticket = 166;
private Object obj = new Object();//private static final Object obj = new Object();
public void run() {
synchronized (obj) {
while (true) {
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":卖票, 票号为:" + ticket);
ticket--;
} else {
break;
}
}
}
}
}
(2.2)此时与没加"synchronized"方法一样,因为此时obj不是同一个,即三个线程分别执行了一次"Object obj = new Object();"
处理方法为将"private Object obj = new Object();“改为"private static final Object obj = new Object();”
解决方法: 2.同步方法(将同步的代码放进一个方法内)
2.1应用于Runnable接口
//2.1
public class WindowTest02 {
public static void main(String[] args) {
Window02 w1 = new Window02();
Thread t1 = new Thread(w1);
Thread t2 = new Thread(w1);
Thread t3 = new Thread(w1);
t1.start();
t2.start();
t3.start();
}
}
class Window02 implements Runnable{
private int ticket = 100;
@Override
public void run() {
while (true){
show();
if (ticket <= 0){
break;
}
}
}
private synchronized void show(){
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":卖票, 票号为:" + ticket);
ticket--;
}
}
}
2.2应用于继承Thread类
//2.2
public class WindowTest1 {
public static void main(String[] args) {
Window1 w1 = new Window1();
Window1 w2 = new Window1();
Window1 w3 = new Window1();
w1.setName("窗口一");
w2.setName("窗口二");
w3.setName("窗口三");
w1.start();
w2.start();
w3.start();
}
}
class Window1 extends Thread {
private static int ticket = 166;
public void run() {
while (true) {
show();
if (ticket <= 0){
break;
}
}
}
public static synchronized void show(){
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":卖票, 票号为:" + ticket);
ticket--;
}
}
}
总结
同步代码块
1.操作需要同步的代码,即可能出现线程安全问题的代码;
2.共享数据,多个线程共同操作的变量,比如ticket;
3.同步监视器→锁,任何一个类的对象,都可以充当锁(如obj);
同步方法
1.与同步代码块相比,仍涉及同步监视器,只是不需要显示声明
2.非静态的同步方法,同步监视器是:this;
本文简单分享了处理线程安全问题的方法,如有错误地方,请不吝赐教!
Tip:
附上尚硅谷宋老师线程讲解视频,小伙伴们可以看看,链接:处理线程安全问题