什么是线程
线程是进程内的执行单元
线程的基本操作
image.png新建线程
image.png为什么呢?看看源码
image.png
image.png
image.png
停止线程
Thread.stop() 不推荐使用。它会释放所有monitor
示例:
image.png
线程中断(怎么优雅的让一个线程停止运作)
示例1:如果仅仅是下面这样的方式
线程并不会终止,虽然已经通知它中断运行了,但是没有作相应的判断标志位,所以线程并不会去理会这个中断通知
示例2:(优雅的方式)
补充:
public void Thread.interrupt() // 中断线程
public boolean Thread.isInterrupted() // 判断是否被中断
public static boolean Thread.interrupted() // 判断是否被中断,并清除当前中断状态
示例三:
挂起( suspend)和继续执行( resume)线程
image.png– suspend()不会释放锁
– 如果加锁发生在resume()之前 ,则死锁发生
- 为什么?看看源码
@Deprecated
public final void suspend() {
checkAccess();
suspend0();
}
解释怎么说?
@deprecated This method has been deprecated, as it is
* inherently deadlock-prone. If the target thread holds a lock on the
* monitor protecting a critical system resource when it is suspended, no
* thread can access this resource until the target thread is resumed. If
* the thread that would resume the target thread attempts to lock this
* monitor prior to calling <code>resume</code>, deadlock results. Such
* deadlocks typically manifest themselves as "frozen" processes.
代码实现:
package someTest;
public class BadSuspend {
public static Object u=new Object();
static ChangeObjectThread t1=new ChangeObjectThread("t1");
static ChangeObjectThread t2=new ChangeObjectThread("t2");
public static class ChangeObjectThread extends Thread{
public ChangeObjectThread(String name) {
super.setName(name);
}
@Override
public void run() {
synchronized (u) {
System.out.println("in "+getName());
Thread.currentThread().suspend();
}
}
}
public static void main(String[] args) throws InterruptedException {
t1.start();
Thread.sleep(100);
t2.start();
t1.resume();
t2.resume();
t1.join();
t2.join();
}
}
上面这个程序就会卡在主程序里面出不来,因为t2的resume()方法先执行,suspend()方法后执行,导致t2一直卡在suspend挂起状态出不来,所以就卡住了。
等待线程结束( join)和谦让(yeild)
- yield:我把cpu让出来,大家一起竞争,给大家一个竞争的机会,当然自己还是有可能再次获得cpu的执行权
- join:
public class JoinMain {
public volatile static int i=0;
public static class AddThread extends Thread{
@Override
public void run() {
for(i=0;i<10000000;i++);
}
}
public static void main(String[] args) throws InterruptedException {
AddThread at=new AddThread();
at.start();
at.join();
System.out.println(i);
}
}
上面示例表示主线程在at.join();等待at
这个线程先执行完,再往下走
join的本质:让所有等待当前线程的其他线程等待
join的本质
while (isAlive()) {
wait(0);
}
image.png
当然,等待的时间也是可以设置的,比如我想等待一段时间以后就不等了^^
建议:
image.png
源码里面直接说明,建议不要使用Thread对象实例的wait和notify方法,因为这些方法操作系统会进行调用,你调用了不保证达到理想的效果
守护线程
- 在后台默默地完成一些系统性的服务,比如垃圾回收线程、 JIT线程就可以理解为守护线程
- 当一个Java应用内,只有守护线程时, Java虚拟机就会自然退出
package someTest;
public class DaemonDemo {
public static class DaemonT extends Thread{
public void run() {
while(true) {
System.out.println("I am alive");
try {
Thread.sleep(1000);
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
Thread t=new DaemonT();
t.setDaemon(true);
t.start();
}
}
上面这个程序运行起来后,啪--就停了,因为它被设置为了守护线程,满足上面的第二条性质
线程优先级
public final static int MIN_PRIORITY = 1;
public final static int NORM_PRIORITY = 5;
public final static int MAX_PRIORITY = 10;
image.png
- 高优先级的线程更容易再竞争中获胜,概率问题,结果不保证
线程同步操作
- synchronized
– 指定加锁对象:对给定对象加锁,进入同步代码前要获得给定对象的锁。
– 直接作用于实例方法:相当于对当前实例加锁,进入同步代码前要获得当前实例的锁。
– 直接作用于静态方法:相当于对当前类加锁,进入同步代码前要获得当前类的锁。
package someTest;
public class AccountingAsync implements Runnable{
static AccountingAsync instance=new AccountingAsync();
static int i=0;
@Override
public void run() {
for(int j=0;j<10000;j++) {
synchronized(instance) {
i++;
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1=new Thread(instance);
Thread t2=new Thread(instance);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}
以上正确输出20000
根据synchronized
修饰的位置不同,有不同的作用域,所以在使用锁的时候一定要注意用到合适的对象上,比如将这个关键字用在静态方法上,就相当于对类进行加锁,结果还是20000
package someTest;
public class AccountingAsync implements Runnable{
static AccountingAsync instance=new AccountingAsync();
static int i=0;
public static synchronized void increase() {
i++;
}
@Override
public void run() {
for(int j=0;j<10000;j++) {
increase();
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1=new Thread(instance);
Thread t2=new Thread(instance);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}
Object.wait() Obejct.notify()
Object.wait():使线程等待在当前对象上
Obejct.notify():通知等待在当前对象上的线程
- 注意事项:以上两个方法必须要在拿到对象监视器锁以后才能调用,没拿到以前是不能调用的,同时如果一个线程拿到了对象监视器锁,然后调用wait()方法就会释放当前对象的监视器锁,而notify方法不一样,不会立即释放,而是等它执行完了再释放
网友评论