一:同步代码块的方式解决线程的安全问题(共享数据)
< 若创建线程的方式是继承Thread类,使用同步代码块(锁)时为了确定锁的唯一性,需要将对象声明为Static类型。
< 若创建线程的方式为实现 Runnable 接口的方式,可以直接将对象放入,通过实现的方式创建多线程,本身就是共享了同一个对象。
<使用同步代码块包围操作共享数据的操作时,必须确定不能多包围也不能少包围。
- 未加锁时的卖票程序(继承Thread类的方式创建的多线程)
public class WindowTest {
public static void main(String[] args) {
Window window = new Window();
Window window1 = new Window();
Window window2 = new Window();
window.setName("窗口一");
window1.setName("窗口二");
window2.setName("窗口三");
window.start();
window1.start();
window2.start();
}
}
class Window extends Thread{
private static int tickets=100;
@Override
public void run() {
while(true){
if (tickets>0){
System.out.println(Thread.currentThread().getName()+":卖票,票号为:"+tickets);//此时的静态变量是不允许声明,但是可以使用
tickets--;
}else{
break;
}
}
}
}
- 会出现重票的现象
窗口二:卖票,票号为:100
窗口一:卖票,票号为:100
窗口三:卖票,票号为:100
- 通过同步代码块解决重票问题(继承Thread类的线程)
class Window extends Thread{
private static int tickets=100;
static Object object=new Object();//继承Thread 类的方式实现多线程加锁需要确保锁的唯一性
@Override
public void run() {
while(true){
synchronized(object){
if (tickets>0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":卖票,票号为:"+tickets);//此时的静态变量是不允许声明,但是可以使用
tickets--;
}else{
break;
}}
}
}
}
- 通过同步代码块解决重票问题(实现Runnable接口的方式创建的线程)
public class WindowTest {
public static void main(String[] args) {
Windows windows = new Windows();
Thread thread = new Thread(windows);//多个线程共享同一个windows对象
Thread thread1 = new Thread(windows);
Thread thread2 = new Thread(windows);
thread.setName("窗口1");
thread1.setName("窗口2");
thread2.setName("窗口3");
thread.start();
thread1.start();
thread2.start();
}
}
class Windows implements Runnable{
private int tickets=100;
Object object=new Object();
@Override
public void run() {
while(true){
synchronized (object){//所有线程都用同一把锁
if (tickets>0){
System.out.println(Thread.currentThread().getName()+":卖票,票号为:"+tickets);//此时的静态变量是不允许声明,但是可以使用
tickets--;
}else{
break;
}
}}
}
}
二:同步方法的方式解决线程安全问题
< 将操作共享数据的代码放在使用被synchronized关键字修饰的方法中
< 同样也必须确保同步方法的唯一性,当一个线程在操作共享数据时,其他的线程是绝对不允许进入的。
public class WindowTest02 {
public static void main(String[] args) {
Sole sole = new Sole();
Thread thread = new Thread(sole);
Thread thread1 = new Thread(sole);
Thread thread2 = new Thread(sole);
thread.setName("窗口1");
thread1.setName("窗口2");
thread2.setName("窗口3");
thread.start();
thread1.start();
thread2.start();
}
}
class Sole implements Runnable{
private static int flags=100;
@Override
public void run() {
while (true){
show();
}
}
public synchronized void show (){//始终确保操作共享数据时只有一个线程在操作,其他线程始终是等待的
if (flags>0){
System.out.println(Thread.currentThread().getName()+"卖票为"+flags);
flags--;
}
}
}