一、先看两个类
1 、Ticket ,它实现了Runnable接口
package thread;
public class Ticket implements Runnable{
private int tick=100;
@Override
public void run() {
try {
printTick();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void printTick() throws InterruptedException {
while (true){
if (tick>0){
System.out.println(Thread.currentThread().getName()+"---tick为: "+tick--);
}else {
break;
}
}
}
}
2 、测试类
package thread;
public class Test01 {
public static void main(String[] args) {
Ticket ticket=new Ticket();
//创建三个线程
Thread thread1=new Thread(ticket);
Thread thread2=new Thread(ticket);
Thread thread3=new Thread(ticket);
//为三个线程起名字
thread1.setName("tick窗口1");
thread2.setName("tick窗口2");
thread3.setName("tick窗口3");
//start线程,让这三个线程到就绪状态(线程的状态)
thread1.start();
thread2.start();
thread3.start();
}
}
执行测试类Test1 的 main函数,执行结果:
此时线程是不安全的,多个线程访问同一个资源(ticket对象里的属性tick),可能线程一执行到中间某个时刻,线程二就进来访问了同一个资源。
如果线程一在改数据之前,线程二就访问了数据,此时线程一和线程二的拿到的数据是一样的,但在线程一执行完数据的修改操作后,这时线程一和线程二拿到的数据就不一样了,也就是不同步。
也就会出现上面的运行结果。
二、那怎么让它同步?
- 用锁,同一个资源的多个线程共用一把锁。
- 对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以参与执行。
- 在代码上的体现就是把public void printTick() throws InterruptedException 方法改为public synchronized void printTick() throws InterruptedException
package thread;
public class Ticket implements Runnable{
private int tick=100;
@Override
public void run() {
try {
printTick();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void printTick() throws InterruptedException {
while (true){
if (tick>0){
System.out.println(Thread.currentThread().getName()+"---tick为: "+tick--);
}else {
break;
}
}
}
}
这次的运行结果:
从结果上看是线程安全了,但是只有一个线程在执行,为什么?
因为线程一执行之后一直拿着锁,没有释放。
三、怎么才能让线程一释放锁?
1. 当前线程的同步方法、同步代码块执行结束后,会释放锁
我们把while循环拿掉,这样就可以演示这种情况。
package thread;
public class Ticket implements Runnable{
private int tick=100;
@Override
public void run() {
try {
printTick();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void printTick() throws InterruptedException {
if (tick>0){
System.out.println(Thread.currentThread().getName()+"---tick为: "+tick--);
}
}
}
while循环拿掉后的运行结果:
2.当前线程在同步代码块、同步方法中执行了线程对象的wait()方法,当前线程暂停,并释放锁。
package thread;
public class Ticket implements Runnable{
private int tick=100;
@Override
public void run() {
try {
printTick();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void printTick() throws InterruptedException {
while (true){
if (tick>0){
System.out.println(Thread.currentThread().getName()+"---tick为: "+tick--);
wait(10);
}else {
break;
}
}
}
}
加wait(20);掉后的运行结果:
这次就可以看到线程的切换了
四、不会释放锁的操作:
线程执行同步代码块或同步方法时,程序调用Thread.sleep()、
Thread.yield()方法暂停当前线程的执行
package thread;
public class Ticket implements Runnable{
private int tick=100;
@Override
public void run() {
try {
printTick();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void printTick() throws InterruptedException {
while (true){
if (tick>0){
System.out.println(Thread.currentThread().getName()+"---tick为: "+tick--);
Thread.sleep(2000);
// Thread.yield();
}else {
break;
}
}
}
}
有Thread.sleep(2000);执行的结果:
有Thread.yield();执行的结果:
这两种情况都是只有一个线程在运行,就是不释放锁,不让其他线程参与进来。
有问题欢迎批评指教
版权声明:本文为weixin_50396443原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。