线程
获取线程相关信息的方法
package thread;
/**
* 获取线程相关信息的一组方法
*/
public class ThreadInfoDemo {
public static void main(String[] args) {
Thread main = Thread.currentThread();//获取主线程
String name = main.getName();//获取线程的名字
System.out.println("名字:"+name);
long id = main.getId();//获取该线程的唯一标识
System.out.println("id:"+id);
int priority = main.getPriority();//获取该线程的优先级
System.out.println("优先级:"+priority);
boolean isAlive = main.isAlive();//该线程是否活着
System.out.println("是否活着:"+isAlive);
boolean isDaemon = main.isDaemon();//是否为守护线程
System.out.println("是否为守护线程:"+isDaemon);
boolean isInterrupted = main.isInterrupted();//是否被中断了
System.out.println("是否被中断了:"+isInterrupted);
}
}
优先级
线程start后会纳入到线程调度器中统一管理,线程只能被动的被分配时间片并发运行,而无法主动索取时间片.线程调度器尽可能均匀的将时间片分配给每个线程.
线程有10个优先级,使用整数1-10表示
- 1为最小优先级,10为最高优先级.5为默认值
- 调整线程的优先级可以最大程度的干涉获取时间片的几率.优先级越高的线程获取时间片的次数越多,反之则越少.
package thread;
public class PriorityDemo {
public static void main(String[] args) {
Thread max = new Thread(){
public void run(){
for(int i=0;i<10000;i++){
System.out.println("max");
}
}
};
Thread min = new Thread(){
public void run(){
for(int i=0;i<10000;i++){
System.out.println("min");
}
}
};
Thread norm = new Thread(){
public void run(){
for(int i=0;i<10000;i++){
System.out.println("nor");
}
}
};
min.setPriority(Thread.MIN_PRIORITY);//设置为最小的优先级
max.setPriority(Thread.MAX_PRIORITY);
min.start();
norm.start();
max.start();
}
}
sleep阻塞
线程提供了一个静态方法:
- static void sleep(long ms)
- 使运行该方法的线程进入阻塞状态指定的毫秒,超时后线程会自动回到RUNNABLE状态等待再次获取时间片并发运行.
- package thread;
- sleep方法处理异常:InterruptedException.
- 当一个线程调用sleep方法处于睡眠阻塞的过程中,该线程的interrupt()方法被调用时,sleep方法会抛出该异常从而打断睡眠阻塞.
public class SleepDemo {
public static void main(String[] args) {
System.out.println("程序开始了!");
try {
Thread.sleep(5000);//主线程阻塞5秒钟
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("程序结束了!");
}
}
意思就是线程0一直在走,要走很久,如果我在线程1中国加一个interrupt(),中断线程0中的sleep的话整个主线程就会结束
public class SheepDemo2 {
public static void main(String[] args) {
Thread lin = new Thread(){
public void run(){
System.out.println("林:我刚美容完,睡一会觉吧");
try {
Thread.sleep(50000000);
} catch (InterruptedException e) {
System.out.println("林:干嘛呢!干嘛呢!干嘛呢!都破了相了!");
}
System.out.println("林:醒了");
}
};
Thread huang = new Thread(){
public void run(){
System.out.println("黄:大锤80,小锤40,开始砸墙!");
for(int i=0;i<5;i++){
System.out.println("黄:80!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
System.out.println("哐当!");
System.out.println("黄:大哥!搞定!");
lin.interrupt();//中断lin线程的睡眠阻塞
}
};
lin.start();
huang.start();
}
}
守护线程
守护线程也称为:后台线程
- 守护线程是
通过普通线程调用setDaemon(boolean on)方法设置而来的,
因此创建上与普通线程无异.
- 守护线程的结束时机上有一点与普通线程不同,即:进程的结束.
- 进程结束:当一个进程中的所有普通线程都结束时,进程就会结束,此时会杀掉所有正在运行的守护线程.
- 线程也分为两种,用户线程和守护线程。
public class DaemonThreadDemo {
public static void main(String[] args) {
Thread rose = new Thread(){
public void run(){
for(int i=0;i<5;i++){
System.out.println("rose:let me go!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
System.out.println("rose:啊啊啊啊啊啊AAAAAAAaaaaa....");
System.out.println("噗通");
}
};
Thread jack = new Thread(){
public void run(){
while(true){
System.out.println("jack:you jump!i jump!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
}
};
rose.start();
jack.setDaemon(true);//设置守护线程必须在线程启动前进行
jack.start();
}
}
通常当我们不关心某个线程的任务什么时候停下来,它可以一直运行,但是程序主要的工作都结束时它应当跟着结束时,这样的任务就适合放在守护线程上执行.比如GC就是在守护线程上运行的
join方法
线程提供了一个方法:void join()
- 该方法允许调用这个方法的线程在该方法所属线程上等待(阻塞),直到该方法所属线程结束后才会解除等待继续后续的工作.所以join方法可以用来协调线程的同步运行.
- 同步运行:多个线程执行过程存在先后顺序进行.
- 异步运行:多个线程各干各的.线程本来就是异步运行的.
public class JoinDemo {
//图片是否下载完毕
public static boolean isFinish = false;
public static void main(String[] args) {
/*
当一个方法的局部内部类中引用了这个方法的其他局部变量时,这个变量
必须是final的。
*/
// final boolean isFinish = false;
Thread download = new Thread(){
public void run(){
for(int i=1;i<=100;i++){
System.out.println("down:"+i+"%");
try {
Thread.sleep(50);
} catch (InterruptedException e) {
}
}
System.out.println("down:下载完毕!");
isFinish = true;
}
};
Thread show = new Thread(){
public void run(){
try {
System.out.println("show:开始显示文字...");
Thread.sleep(3000);
System.out.println("show:显示文字完毕!");
/*
显示图片前要等待download执行完毕
*/
System.out.println("show:开始等待download...");
download.join();//show线程阻塞,直到download执行完毕
System.out.println("show:等待download完毕!");
System.out.println("show:开始显示图片...");
if(!isFinish){
throw new RuntimeException("show:显示图片失败!");
}
System.out.println("show:显示图片完毕!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
download.start();
show.start();
}
}
download.join();//show线程阻塞,直到download执行完毕
适用于文字显示完了,但是图片还在加载
同步块
有效的缩小同步范围可以在保证并发安全的前提下尽可能的提高并发效率.同步块可以更准确的控制***需要多个线程排队执行的代码片段.***
synchronized(同步监视器对象){
需要多线程同步执行的代码片段
}
`public class SyncDemo2 {
public static void main(String[] args) {
Shop shop = new Shop();
Thread t1 = new Thread(){
public void run(){
shop.buy();
}
};
Thread t2 = new Thread(){
public void run(){
shop.buy();
}
};
t1.start();
t2.start();
}
}
class Shop{
public void buy(){
/*
在方法上使用synchronized,那么同步监视器对象就是this。
*/
// public synchronized void buy(){
Thread t = Thread.currentThread();//获取运行该方法的线程
try {
System.out.println(t.getName()+":正在挑衣服...");
Thread.sleep(5000);
/*
使用同步块需要指定同步监视器对象,即:上锁的对象
这个对象可以是java中任何引用类型的实例,只要保证多个需要排队
执行该同步块中代码的线程看到的该对象是"同一个"即可
*/
synchronized (this) {
// synchronized (new Object()) {//没有效果!
System.out.println(t.getName() + ":正在试衣服...");
Thread.sleep(5000);
}
System.out.println(t.getName()+":结账离开");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
synchronized同步关键字可以用来修饰代码块,称为同步代码块,使用的锁对象类型任意,但注意:必须唯一!
synchronized同步关键字可以用来修饰方法,称为同步方法
同步的缺点是会降低程序的执行效率,但我们为了保证线程的安全,有些性能是必须要牺牲的
但是为了性能,加锁的范围需要控制好,比如我们不需要给整个商场加锁,试衣间加锁就可以了