多线程核心技术 Chapter1
Posted tbricks24
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程核心技术 Chapter1相关的知识,希望对你有一定的参考价值。
多线程核心技术 技能基础Charpter1
本章需要着重掌握的是
- 线程的启动
- 如何使线程暂停
- 如何使线程停止
- 线程的优先级
线程安全相关的问题
1.1 进程和多线程的概念及多线程的优点
1.2 使用多线程
1.2.1 继承Thread类
1.2.2 实现Runnable接口
1.2.3 实例变量与线程安全
1.2.4 留意i-- 与 System.out.println()的异常
1.3 currentThread()方法
1.4 isAlive()方法
1.5 sleep()方法
1.6 getId()方法
1.7 停止线程(异常法)
/**
* stop()方法已经弃用,unsafe
* interrupted()判断中断状态、并清除状态
* isInterrupted()判断中断状态,不清除状态
* interrupt() 停止线程的主要方法,但他不是真正终止一个正在运行的线程,只是在当前线程中打上一个停止标记,还需要加入一个判断才可以完成线程停止.
* @author Hasee
*
*/
public class Test11 {
public static void main(String[] args) {
try {
// Thread.currentThread().interrupt();
MyThread11 thread = new MyThread11();
thread.start();
Thread.sleep(2000);
thread.interrupt();
System.out.println("是否停止1? =" + Thread.currentThread().isInterrupted());
System.out.println("是否停止2? =" + Thread.currentThread().isInterrupted());
}
catch (InterruptedException e) {
System.out.println("main catch");
e.printStackTrace();
}
System.out.println("end!");
}
}
class MyThread11 extends Thread {
@Override
public void run() {
for (int i = 0; i < 500; i++) {
System.out.println("i=" + (i + 1));
}
}
}
以上可以看出当前线程是main,所以从未中断过.
/**
* 同样来看下段代码
*
* @author Hasee
*
*/
public class Test14 {
public static void main(String[] args) {
try {
MyThread11 thread = new MyThread11();
thread.start();
Thread.sleep(1000);// 暂停当前线程1s
thread.interrupt();
System.out.println("是否停止1? =" + thread.isInterrupted());
System.out.println("是否停止2? =" + thread.isInterrupted());
} catch (InterruptedException e) {
System.out.println("main catch");
e.printStackTrace();
}
System.out.println("end!");
}
}
可以看出,isInterrupted()并不清除状态.
/**
* 在for循环中避免出现bug,可以抛出中断异常来处理
* @author Hasee
*
*/
public class Test13 {
public static void main(String[] args) {
try {
MyThread13 thread = new MyThread13();
thread.start();
Thread.sleep(2000);
thread.interrupt();
} catch (InterruptedException e) {
}
}
}
class MyThread13 extends Thread {
@Override
public void run() {
super.run();
try {
for (int i = 0; i < 500000; i++) {
if (this.isInterrupted()) {
System.out.println("isInterrupted = " + this.isInterrupted());
System.out.println("已经是停止状态了,我要退出.");
throw new InterruptedException();
}
System.out.println("i=" + (i + 1));
}
System.out.println("我在for下面");
} catch (InterruptedException e) {
System.out.println("进MyThread13类的run方法中的catch了!");
e.printStackTrace();
}
System.out.println("end.");
}
}
如果不抛出异常的话,直接break会执行for循环之后的语句,没有达到中断的效果.这个叫做停止线程--异常法.
1.7.1在沉睡中停止
/**
* 在沉睡中停止
* @author Hasee
*
*/
public class Test15 {
public static void main(String[] args) {
try {
MyThread16 thread2 = new MyThread16();
thread2.start();
thread2.interrupt();
System.out.println("end!");
MyThread15 thread = new MyThread15();
thread.start();
Thread.sleep(200);
thread.interrupt();
} catch (InterruptedException e) {
System.out.println("main catch");
}
System.out.println("end!");
}
}
//主方法中先sleep再用interrupt()
class MyThread15 extends Thread {
@Override
public void run() {
super.run();
try {
System.out.println("run begin");
Thread.sleep(200000);
System.out.println("run end");
} catch (InterruptedException e) {
System.out.println("在沉睡中被停止! 进入catch!" + this.isInterrupted());
e.printStackTrace();
}
}
}
//
class MyThread16 extends Thread {
@Override
public void run() {
super.run();
try {
for(int i = 0; i < 10000; i++) {
System.out.println("i=" + (i+1));
}
System.out.println("run begin");
Thread.sleep(200000);
System.out.println("run end");
} catch (Exception e) {
System.out.println("先停止,再遇到sleep!进入catch");
e.printStackTrace();
}
}
}
以上是在沉睡中停止,可以先sleep和后sleep
1.7.2 stop()暴力停止,已经弃用
使用stop()释放锁会给数据造成不一致性的结果.
示例如下:
public class TestStop1 {
public static void main(String[] args) {
try {
SynchronizedObject object = new SynchronizedObject();
MyThreadStop1 mts1 = new MyThreadStop1(object);
mts1.start();
Thread.sleep(500);
mts1.stop();//强制停止,不建议在程序中用stop()
System.out.println(object.getUsername() + " " + object.getPassword());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class SynchronizedObject {
private String username = "a";
private String password = "aa";
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
synchronized public void printString(String username, String password) {
try {
this.username = username;
Thread.sleep(100000);
this.password = password;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class MyThreadStop1 extends Thread {
private SynchronizedObject object;
public MyThreadStop1(SynchronizedObject object) {
this.object = object;
}
@Override
public void run() {
super.run();
object.printString("b", "bb");
}
}
1.7.3 使用return停止线程
就是直接判断isInterrupted()状态后进行return,建议还是使用抛异常来操作
1.8 暂停线程(线程可恢复)
1.8.1 suspend和resume方法的使用
- 可用suspend来暂停线程
- 可用resume来恢复线程
示例如下:
public class TestSuspend_Resume {
public static void main(String[] args) {
try {
Suspend_Resume_Thread thread = new Suspend_Resume_Thread();
thread.start();
Thread.sleep(5000);
// A段
thread.suspend();
System.out.println("A= " + System.currentTimeMillis() + " i=" + thread.getI());
Thread.sleep(5000);
System.out.println("A= " + System.currentTimeMillis() + " i=" + thread.getI());
// B段
thread.resume();
Thread.sleep(5000);
// C段
thread.suspend();
System.out.println("B= " + System.currentTimeMillis() + " i=" + thread.getI());
Thread.sleep(5000);
System.out.println("B= " + System.currentTimeMillis() + " i=" + thread.getI());
} catch (Exception e) {
e.printStackTrace();
}
}
}
class Suspend_Resume_Thread extends Thread {
private long i = 0;
public long getI() {
return i;
}
public void setI(long i) {
this.i = i;
}
@Override
public void run() {
super.run();
while (true)
i++;
};
}
1.8.2 suspend与resume方法的缺点——独占
造成公共的同步对象的独占,使得其他线程无法访问公共同步对象。
如下示例:
public class TestResume_Suspend2 {
public static void main(String[] args) {
try {
final SynchronizedObject1 object = new SynchronizedObject1();
Thread thread1 = new Thread() {
public void run() {
object.printString();
};
};
thread1.setName("a");
thread1.start();
Thread.sleep(1000);
Thread thread2 = new Thread() {
public void run() {
System.out.println("thread2启动了,但进入不了printString方法!,只打印1个begin");
System.out.println("因为printString()方法被a线程锁定并且永远suspend暂停了!");
object.printString();//不能再被访问
};
};
thread2.start();
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("I love YJY");;
}
}
}
class SynchronizedObject1{
synchronized public void printString() {
System.out.println("begin");
if(Thread.currentThread().getName().equals("a")) {
System.out.println("a线程永远suspend了!");
Thread.currentThread().suspend();
}
}
}
以上代码即锁死了Object调用pringString()方法。
特别要注意System.out.println()方法是带同步锁的,如果内部suspend的话,同步锁没有被释放,会造成死锁。
suspend与resume方法的缺点——不同步
因为暂停而导致数据不同步。
public class TestResume_Suspend3 {
public static void main(String[] args) {
try {
final MyObject object = new MyObject();
Thread thread1 = new Thread() {
public void run() {
object.setValue("a", "aa");
};
};
thread1.setName("a");
thread1.start();
Thread.sleep(500);
Thread thread2 = new Thread() {
public void run() {
object.printUsernamePassword();
};
};
thread2.start();
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("I love YJY");
}
}
}
class MyObject {
private String username = "1";
private String password = "11";
public void setValue(String u, String p) {
this.username = u;
//如果当前线程名为a,则进行线程暂停
if (Thread.currentThread().getName().equals("a")) {
System.out.println("停止a线程!");
Thread.currentThread().suspend();
}
this.password = p;
}
public void printUsernamePassword() {
System.out.println(username + " " + password);
}
}
以上即为不同步的情况。
1.9 yield方法
该方法作用是放弃当前的cpu资源,将它让给其他的任务去占用cpu执行时间,但放弃的时间不确定。
public class TestYield {
public static void main(String[] args) {
YieldThread thread = new YieldThread();
thread.start();
}
}
class YieldThread extends Thread {
@Override
public void run() {
long beginTime = System.currentTimeMillis();
int count = 0;
for (int i = 0; i < 5000000; i++) {
Thread.yield();//将CPU让给其它资源导致最终执行完的速度变慢
count = count + (i + 1);
}
long endTime = System.currentTimeMillis();
System.out.println("用时:" + (endTime - beginTime) + "毫秒!");
}
}
1.10 线程的优先级
- 优先级较高的线程得到的CPU资源较多
- 线程优先具有继承性---->比如A线程启动B线程,则B线程的优先级与A是一样的
- 高优先级总是大部分先执行完,但不代表高优先级的线程总是全部先执行完
- 当线程优先级的等级差距很大时,谁先执行完和代码的调用顺序无关
- 即优先级越高,CPU尽量将执行资源让给优先级高的线程,1-10,10是最高优先级
- 优先级具有随机性,优先级较高的线程不一定每一次都先执行完
1.11 守护线程
Java中有两种线程,一种是用户线程,另外一种就是守护线程(Daemon线程)
典型的守护进程就是垃圾回收线程,当进程中没有非守护线程了,则垃圾回收线程也就没有存在的必要的。
GC就是典型的垃圾回收器。
总结
主要就是开篇的几个要点,然后对API的使用,以及Synchronized关键字的基本使用。
以上是关于多线程核心技术 Chapter1的主要内容,如果未能解决你的问题,请参考以下文章