启动线程
1.Runnable是Thread执行的逻辑
2.CallableFutureTask也是Thread要执行的逻辑,只是封装了获取结果的功能
因此: 启动线程的方式只有一种: new Thread().start();
终止线程
1.stop(不建议使用)
示例代码:
public class Demo_Stop {
public static void main(String[] args) throws InterruptedException {
MyThread thread = new MyThread();
thread.start();
// 休眠1秒,确保i变量自增成功
Thread.sleep(1000);
thread.stop();
// 确保线程已经终止
while (thread.isAlive()) {}
// 输出结果
thread.print();
}
}
class MyThread extends Thread {
private int i = 0, j = 0;
@Override
public void run() {
synchronized (this) {
++i;
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
++j;
}
System.out.println("锁释放。。。");
}
public void print() {
System.out.println("i=" + i + " j=" + j);
}
}
打印结果:
需要的输出结果应该是i=0 j=0;
stop方法没有保证同步代码看块中的数据一致性, 出现了线程安全问题
2.interrupt
示例代码:
public static void main(String[] args) throws InterruptedException {
Thread workThread = new Thread(new Runnable() {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
System.out.println("运行中");
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
e.printStackTrace();
//将擦除掉的isInterrupted状态补上
Thread.currentThread().interrupt();
}
}
}
});
workThread.start();
Thread.sleep(3000L);
workThread.interrupt();
}
注意点:
1.interrupt方法并不会中断线程,只是打上了中断标记
示例代码:
public static void main(String[] args) throws InterruptedException {
//开启一个线程
Thread testThread = new Thread(){
@Override
public void run() {
while(true){
System.out.println("isInterrupted:" + Thread.currentThread().isInterrupted());
System.out.println("state:" + Thread.currentThread().getState());
}
}
};
testThread.start();
Thread.sleep(2000);
//调用interrupt方法,不会改变线程状态
//并不会让线程退出,只是做了一个interrupt标记
testThread.interrupt();
}
输出结果:
可以看到,在sleep2秒后,isInterrupted的状态值由false变为了true
2.如果该线程在调用 wait(),wait(long)方法,join() 、 join(long, int) 、join(long, int)、sleep(long, int)或sleep(long, int)等方法后,处于WAITING、Timed Waiting状态时,在该线程被调用interrupt方法后,线程的WAITING、Timed Waiting状态将被清除,并抛出InterruptedException异常。
示例代码:
public static void main(String[] args) throws InterruptedException {
Thread testThread = new Thread(){
@Override
public void run() {
while (true){
try {
System.out.println("running...");
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
/*
当线程处于 Waiting、TimedWaiting状态,
执行interrupted方法后,会从Waiting、TimedWaiting中退出
并且isInterrupted=true的信号被擦除
*/
System.out.println(Thread.currentThread().getState());
System.out.println("isInterrupted:" + Thread.currentThread().isInterrupted());
}
}
}
};
testThread.start();
Thread.sleep(1000);
testThread.interrupt();
}
打印结果:
3.如果目标线程是被I/O 或者NIO中的Channel所阻塞,同样,I/O操作会被中断或者返回特
殊异常值。
4.park()\parkNanos方法执行后,线程也处于 WAITING、Timed Waiting,也会被唤醒,但是不会抛异常,且有很诡异的情况发生。
示例代码:
public static void main(String[] args) throws InterruptedException {
Thread testThread = new Thread(new Runnable() {
@Override
public void run() {
while(true){
LockSupport.park();
System.out.println("ing...");
}
}
});
testThread.start();
Thread.sleep(1000L);
testThread.interrupt();
System.out.println("============end=============================");
}
打印结果
deamon线程
定义:
守护线程
是指在程序运行的时候在后台提供一种通用服务的线程,
进程结束时,会杀死所有守护线程。
注意点:
1.在Daemon线程中产生的新线程也是Daemon的
2.不能把正在运行的常规线程设置为守护线程,thread.setDaemon(true)必须在thread.start()之前设置,否则会跑出一个IllegalThreadStateException异常。
3.守护线程它会在任何时候甚至在一个操作的中间发生中断,因此应该永远不去访问固有资源,如文件、数据库等等
CountDownLatch倒计时器
作用:
countDownLatch可以使一个线程等待其他线程各自执行完毕后再执行。
示例代码:
public class Demo_CountDownLatch {
static AtomicLong num = new AtomicLong(0);
public static void main(String args[]) throws InterruptedException {
CountDownLatch ctl = new CountDownLatch(10);
for (int i=0; i< 10; i++){
new Thread(){
@Override
public void run() {
for (int j=0; j< 1000; j++){
num.getAndIncrement();
}
ctl.countDown();
}
}.start();
}
//设置开关,设置门栓
ctl.await();
System.out.println(num.get());
}
}
Semaphore计数信号量
作用:
常用于限制可以访问某些资源(物理或逻辑的)线程数目。
是一种用来控制并发量的共享锁。
示例代码:
public class Demo_Semaphore {
public static void main(String args[]){
Semaphore sp = new Semaphore(10);
//短时间发送1000个请求,并发会很高,数据库会受不了
for (int i=0; i<1000; i++){
new Thread(){
@Override
public void run() {
try {
sp.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
//模拟DB查询
queryDb("localhost:3306");
sp.release();
}
}.start();
}
}
//发送一个HTTP请求
public static void queryDb(String uri) {
System.out.println("query===>: " + uri);
// 类似sleep的作用
LockSupport.parkNanos(1000 * 1000 * 1000);
}
}
CyclicBarrier循环栅栏
作用:
可以循环利用的屏障
示例代码:
public class Demo_CyclicBarrier {
public static void main(String[] args) {
CyclicBarrier barrier = new CyclicBarrier(5,// 栅栏一次通过的请求数
new Runnable() {
@Override
public void run() {
System.out.println(">>> 这是一个栅栏。。。");
}
});
//传入一个Runnable,打印栅栏
for (int i=0; i< 100; i++){
new Thread(){
@Override
public void run() {
try {
barrier.await(); //
System.out.println("请求...");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}.start();
LockSupport.parkNanos(1000 * 1000 * 1000L);
}
}
}