1.线程命名于取得
当我们没有给线程取名字的时候,我们调用getName()函数,会发现系统会自定的给线程起名字为:thread-0,thread-1…显然这样是不好的,当我们又很多线程的时候,线程的名字如果不能见名思意的话,我们就会混淆,所以建议,我们只用线程就给它取名字,线程起名字通过:setName()函数的方法。
public static void main(String[] args) {
ThreadTool task=new ThreadTool();
Thread thread=new Thread(new Runnable() {
@Override
public void run() {
//直接实现了我们代理类里面的功能,不需要再创建一个类了
task.print("hello","nihao");
}
});
thread.start();
// //系统自定义的名字
// System.out.println(thread.getName());
//我们自己给线程起名字
thread.setName("线程-处理PrintInfo");
System.out.println(thread.getName());
}
2.共享变量的两种方式
package com.wschase.xianchengjianjie;
/**
* Author:WSChase
* Created:2019/1/8
*/
public class Thread3 extends Thread {
private static int tick=10;//将它变为类的属性就可以实现共享了
@Override
public void run() {
while(tick>0){
System.out.println(this.getName()+"剩余:"+tick--+"张票");
}
}
public static void main(String[] args) {
//(1)这个是使用Thread来实现的
// Thread3 thread1=new Thread3();
// thread1.setName("Thread-A");
// Thread3 thread2=new Thread3();
// thread2.setName("Thread-B");
// thread1.start();
// thread2.start();
//(2)使用Runnable来实现
Runnable runnable=new Runnable() {
private int tick=10;
@Override
public void run() {
while(tick>0){
//ThreadcurrentThread():表示获得当前线程的名字
System.out.println(Thread.currentThread()+"剩余:"+tick--+"张票");
}
}
};
new Thread(runnable,"Thread-A").start();
new Thread(runnable,"Thread-B").start();
}
}
通过上面的两种方式我们可以看到,Runnable是实现变量共享的方式更加的好、安全。
3.线程命名与取得
package com.wschase.xianchengjianjie;
/**3.多线程的常用操作方法
* Author:WSChase
* Created:2019/1/8
*/
public class ThreadTool {
//这是一个普通任务
public void print(Object ... args){
for(int i=0;i<args.length;i++){
System.out.println(args[i]);
}
}
public static void main(String[] args) {
//我们的main方法就是我们的主线程
ThreadTool task=new ThreadTool();
Thread thread=new Thread(new Runnable() {
@Override
public void run() {
//直接实现了我们代理类里面的功能,不需要再创建一个类了
task.print("hello","nihao");
}
});
thread.start();
// //系统自定义的名字
// System.out.println(thread.getName());
//我们自己给线程起名字
thread.setName("线程-处理PrintInfo");
System.out.println(thread.getName());
}
}
4.线程的各个状态
需要注意的是Sleep方法,并不会释放资源。在多线程里面我们只用资源的时候采用的方法,都是锁定的方法,当我锁定以后别人没有打开这把锁的钥匙,所以别人是使用不了的,必须等到我把资源释放以后才可以使用。但是资源的分配并不是说有资源就可以使用的,还是存在资源竞争。当一个线程运行完成以后这个线程就死亡了。
5.休眠(Sleep)方法
休眠的概念:首先我们需要知道,线程休眠指的是让程序暂停一下,等到休眠时间完成以后我们再进行程序的执行。
但是需要我们注意的是,线程的休眠是交出CPU,让CPU可以取执行其他的任务,但是它并不会将自己资源的锁交出去,所以就算是处于休眠状态,但是这个线程占有的资源并不会释放的,其他线程并不可以使用该线程的资源。
package com.wschase.xianchengjianjie;
import java.time.LocalDateTime;
import java.util.Locale;
/**
* Author:WSChase
* Created:2019/1/8
*/
public class TestSleep {
public static void main(String[] args) {
//最简洁的写法
new Thread(()->{
while (true){
try {
Thread.sleep(1000);//单位是毫秒
System.out.println("当前时间"+LocalDateTime.now());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"Thread-A").start();
}
}
6.线程让步yield()
线程让步有几个特点:
(1)它与sleep()方法是一样的,只是让出CPU时间片段,但是并不会释放锁。
(2)可以获得让出CPU时间片段的必须是和该线程有相同权限的线程。
(3)它让出权限的时间并不是一定的,是不定的,并不受它的控制。
(4)这是它和sleep的区别:使用线程让步yeild()方法并不会到线程的阻塞状态,而是直接到线程的就绪状态,等到下次直接到线程的运行状态。
package com.wschase.xianchengjianjie;
/**线程让步
* Author:WSChase
* Created:2019/1/8
*/
public class TestYield {
public static void main(String[] args) {
Runnable runnable=new Runnable() {
@Override
public void run() {
for(int i=0;i<3;i++){
Thread.yield();
System.out.println(Thread.currentThread().getName());
}
}
};
new Thread(runnable,"Thread-A").start();
new Thread(runnable,"Thread-B").start();
new Thread(runnable,"Thread-C").start();
}
}
对于线程让步我们尽量不要使用。
7.等待该线程终止join()方法
我们在一个线程里面如果调用了其他线程的join()方法,它就会阻塞当前线程,直到我们被调用的线程对象里面的run()方法执行完毕,这个线程才会继续执行。
package com.wschase.xianchengjianjie;
import sun.plugin2.message.Message;
/**
* Author:WSChase
* Created:2019/1/8
*/
public class TestJoin {
//我们在一个线程里面如果调用了其他线程的join()方法,它就会阻塞当前线程,
// 直到我们被调用的线程对象里面的run()方法执行完毕,这个线程才会继续执行。
public static void main(String[] args) throws InterruptedException {
//业务逻辑
MyRunnable runnable=new MyRunnable();
//线程
Thread thread=new Thread(runnable,"Thread-A");
thread.start();
//在主线程中调用线程对象的join方法,会阻塞主线程
//直到调用线程对象的run方法执行完毕,主线程才会继续执行
thread.join();
System.out.println("当前线程"+Thread.currentThread().getName());//main
}
}
class MyRunnable implements Runnable{
private int tick=100;
@Override
public void run() {
while(this.tick>0){
System.out.println(Thread.currentThread().getName()+"tick="+tick--);
}
}
}
作用:如果两个线程A、B的任务有相互依赖的关系,如果 B里面执行的内容依赖于A的结果,它的执行必须等到A执行完成以后才能执行,所以就可以使用我们的join()方法。
8.线程停止
在多线程中有三种方法可以停止线程
(1)设置标记为,线程正常退出
(2)使用stop方法强制退出,但是不安全,现在我们已经不使用这种方法了。
(3)使用Thread类中的一个interrupt()可以中断线程。
package com.wschase.thread2;
/**线程停止
* Author:WSChase
* Created:2019/1/9
*/
// //1.通过标记位的方式让线程终止
//public class TestThread {
// public static void main(String[] args) {
//
// MyRunnable myRunnable=new MyRunnable();
// Thread thread=new Thread(new MyRunnable(),"子线程");
// thread.start();
//
// //主线程休眠
// try {
// Thread.sleep(3000);
//
// //1.修改标记为-->当我们的这个标记为等到3以后就会终止线程
// myRunnable.setFlag(false);
//
//
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
//}
//class MyRunnable implements Runnable{
//
// private boolean flag=true;
// @Override
// public void run() {
// int i=0;
// while(this.flag){
// System.out.println(Thread.currentThread().getName()+"循环执行第"+ ++i+"次");
// try {
// Thread.sleep(1000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
// }
//
// public void setFlag(boolean flag) {
// this.flag = flag;
// }
//}
//2.通过中断让线程停止
public class TestThread {
public static void main(String[] args) {
MyRunnable2 myRunnable2=new MyRunnable2();
Thread thread=new Thread(new MyRunnable2(),"子线程");
thread.start();
//主线程休眠
try {
Thread.sleep(3000);
//Thread的中断方法
thread.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class MyRunnable2 implements Runnable{
@Override
public void run() {
int i=0;
while(true){
System.out.println(Thread.currentThread().getName()+"循环执行第"+ ++i+"次");
try {
//判断线程的中断情况
boolean interruptedStatus = Thread.currentThread().isInterrupted();
//非阻塞情况
if(interruptedStatus){
break;
}
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("阻塞中断:"+Thread.currentThread().isInterrupted());
return;
}
}
}
}
对于中断方式终止线程:我们可以通过异常捕获在catch里面来决定是否要退出程序。
简而言之:当我们调用线程的interrupt方法的时候,它就会把我们中断的标记为改为true。
(1)那么如果是非阻塞情况,线程的中断由我们自己来决定,在程序里面通过异常捕获在catch里面来决定是否要退出程序。
(2)如果在阻塞情况下,阻塞又是由于我们的wait、sleep、join方法引起的,它会将我们的标记为改成一个false,然后再抛一个interruptException。
9.线程优先级
在我们的java中实际上我们的优先级是没有用的。所以在优先级这一块我们只需要直到两个点就可以啦:
(1)线程的优先级越高有可能先执行,并不是一定。
(2)优先级是可以继承的。
package com.wschase.thread2;
/**
* Author:WSChase
* Created:2019/1/9
*/
public class TestThreadyouxianji {
public static void main(String[] args) {
//主线程的优先级
System.out.println("主线程的优先级:"+Thread.currentThread().getPriority());
//在主线程中创建一个线程不指定优先级
Thread threadA=new Thread(()->{
System.out.println(Thread.currentThread().getName()
+"优先级是:"+Thread.currentThread().getPriority());
},"Thread-A");
threadA.start();
//当我们没有改变优先级的时候,这个Thread-A的优先级就是府县丞的优先级:5
threadA.setPriority(6);
}
}
对于优先级的继承:当我们在一个线程里面启动了另外一个线程,并且我们并没有给这个线程指定优先级,那么这个线程的有极限就是我们父线程的优先级。
10.守护线程
在java中我们一共有两种线程:
(1)用户线程
(2)守护线程:通过isDaemon()方法返回的如果是true,就是守护线程,返回false那么就不是守护线程。
守护线程是当我们的用户存在它就得一直工作,只有没有用户线程的时候,它才会同JVM一起停止工作,简言之守护线程就是守护用户线程的。