@TOC
线程中断
interrupt()方法
当前线程如果处于sleep()或join()状态并被其他线程中断的话,会引发中断异常,进入异常处理
如果没有处于sleep()或join()状态使被其他线程中断,不会引发异常,不会进入异常处理
class MyThread1 implements Runnable{
@Override
public void run() {
for(int i = 1; i <= 5; i ++){
System.out.println(Thread.currentThread().getName() + ":" + i);
if(i == 3){
try {
Thread.sleep(1000);//
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName()+ "进入了异常处理");
}
}
}
}
}
public class TestInterrupt {
public static void main(String[] args) {
MyThread1 th = new MyThread1();
Thread t1 = new Thread(th,"t1");
t1.start();
t1.interrupt();// 主线程执行这句代码,即主线程中断t1
}
}
t1:1
t1:2
t1:3
t1进入了异常处理
t1:4
t1:5
线程让步
yield()
让出运行机会给别的线程,但是当前线程也可能继续得到机会
理论上是让给优先级高的或同等优先级的线程;
class Thread2 implements Runnable{
@Override
public void run() {
for(int i = 1; i <= 10; i ++){
System.out.println(Thread.currentThread().getName()+":" + i);
if(Thread.currentThread().getName().equals("t1") && i == 5){
Thread.yield();// 让步
}
}
}
}
public class TestYield {
public static void main(String[] args) {
Thread2 th = new Thread2();
Thread t1 = new Thread(th,"t1");
Thread t2 = new Thread(th,"t2");
t1.setPriority(1);
t2.setPriority(10);
t1.start();
t2.start();
}
}
线程同步
当两个或两个以上的线程需要共享资源,它们需要某种方法来确定在某一刻仅被一个线程占用,达到此目的的过程叫做同步(synchronization)
同步语法:
- 同步方法
synchronized 方法{ }
- 同步代码块
我们可以将某个方法的调用放入一个synchronization 块中
synchronized (对象){
同步块;
}
获得锁:
当线程 需要执行 同步代码块 或 同步方法中的代码时,需要获得锁。
线程获得了锁成功,那么就可以执行同步代码块或同步方法中的代码了,
其它线程处于阻塞状态,只有 此线程释放了锁,其它线程才会继续争夺锁。
释放锁:
- 同步代码块 或 同步方法的代码都执行完了;
- break或return 的时候结束了同步代码块或同步方法;
- 有无法处理的Error或Exception时;
- wait()方法。
通过单例模式了解同步
单例模式有两种实现方法——懒汉式和饿汉式
懒汉式:
//同步方法
class Single{
private static Single single = null;
private Single(){}
synchronized public static Single getSingle(){
if(single == null){
single = new Single();
}
return single;
}
}
//同步代码块
class Single{
/*
*在类加载 初始化结束后 对象没有创建,只有在应用的时候才会创建。
*/
private static Single single = null;//指向自己实例的私有静态引用
private Single(){}
public static Single getSingle(){//以自己实例为返回值的静态的公有方法,静态工厂方法
if(single == null){//第一个判断是为了提高效率,如果已经创建了对象,其他线程就不必争夺锁
synchronized(Single.class){
/*
*第二个if判断的作用:如果t1获得了锁执行了块内容,则对象创建完成
*t1释放锁之后t2获得锁,如果没有这里的if,t2会再次创建对象,就无法保证单例了
*/
if(single == null){
single = new Single();//被动创建对象,在真正需要使用时才去创建
}
}
}
return single;
}
}
public class TestSynThread {
public static void main(String[] args) {
// 多线程
new Thread(new Runnable(){
@Override
public void run() {
System.out.println(Single.getSingle());// 地址
}
},"t1").start();
new Thread(new Runnable(){
@Override
public void run() {
System.out.println(Single.getSingle());// 地址
}
},"t2").start();
}
}
饿汉式:
饿汉式在声明的时候就已经创建了对象,线程运行的时候不会再创建,因此是线程安全的
// 饿汉式
class Single{
//这种写法在类加载的时候一定会创建对象
//但是有时候我们因为某些原因需要加载这个类但是不需要用这个对象
//这样就会造成空间的浪费
//所以我们可以采用一种写法来实现只在调用getSingle方法时才创建对象
private static Single single = new Single();
private Single(){}
public static Single getSingle(){
return single;
}
}
//另一种写法 通过静态内部类
class Single{
private Single(){}
private static class staticSingle{//静态内部类
private static Single single = new Single();
}
public static Single getSingle(){
//只有调用getSingle方法的时候才会加载内部类来创建对象
return Single.staticSingle.single;
}
}
public class TestSynThread5 {
public static void main(String[] args) throws ClassNotFoundException {
//加载初始化类
Class.forName("包名.Single");//只加载Single类,不会加载其内部类
new Thread(new Runnable(){
@Override
public void run() {
System.out.println(Single.getSingle());// 地址
}
},"t1").start();
new Thread(new Runnable(){
@Override
public void run() {
System.out.println(Single.getSingle());// 地址
}
},"t2").start();
}
}
Q.E.D.