2019.07.22(day18)
创建线程
java程序员可以写线程,不需要程序关心线程在哪个进程里
继承Thread类:
public class Mythread extends Thread{
public void run(){
//线程的入口
//线程的业务/任务逻辑
//线程的出口
}
}
使用:
Mythread mt=new Mythread();
mt.start();//调用重写的run方法,实际上是多态
实现Runnable接口:
public class RunLuoji implements Runnable{
public void run(){
//线程的入口
//线程的业务/任务逻辑
//线程的出口
}
}
使用:
Thread t1=new Thread(new RunRuoji());
t1.start();//执行的是Thread中的run方法,由Thread的run方法调用接口的run方法
线程的状态:
创建线程的对象 创建态 Thread t=new Thread();
创建完的线程对象 就绪态 t.start();//拍到线程的队列中,不一定马上获取cpu
获取到cpu的资源 执行态 执行run()方法;//线程出队列
执行到某个点时阻塞 阻塞态 从cpu上下来;//io,sleep,wait等阻塞
正常执行完run方法 结束态/消亡态 等待GC回收
线程的状态转换:
创建态-->就绪态
就绪态-->执行态
执行态-->阻塞态/挂起
执行态-->就绪态
阻塞态-->就绪态
执行态-->结束态/消亡态
结论:
1.根据业务,要考虑有多少个业务逻辑,就写多少个run
2.每一个run要执行多少次
3.执行每一次run,run是否使用数据,要考虑数据的安全性问题
用内部类创建线程对象:
可以用内匿名内部类来创建线程
此方法可以简化代码的复杂度
一个线程仅需一个实例时,用这种方法
方式一:
实现类是匿名的,对象是不是匿名的
Thread t=new Thread(){
public void run(){
System.out.println("run方法");
}
};
t.start();
方式二:
实现类是匿名的,对象也是匿名的
new Thread(){
public void run(){
System.out.println("run方法");
}
}.start();
方式三:
实现类是匿名的,对象不是匿名的
Runnable r=new Runnable(){
public void run(){
System.out.println("run方法");
}
};
Thread t=new Thread(r);
t.start();
方式四:
实现类是匿名的,对象也是匿名的
new Thread(new Runnable(){
public void run(){
System.out.println("run方法");
}
}).start();
方式五:
Thread t=new Thread(new Runnable(){
public void run(){
System.out.println("run方法");
}
});
t.start();
创建对象方法的总结:
1.继承自Thread类,重写run方法
优点:
在当前的线程类中可以获取run方法并重写
同时在当前线程中也可以访问Thread类中的方法
缺点:
当前线程类不能继承其他的类,java是单继承
2.实现Runnable接口,并重写run方法
优点:
当前类可以多实现,还可以继承一次
把线程对象和任务逻辑代码分离出来
缺点:
Runnable接口的实现类只有一个run方法
要想使用其他的线程方法需要
Thread t=new Thread(Runnable接口的实现类对象);
3.特殊的用法,匿名内部类
优点:
写法简单,编码量小
缺点:
run的实现只有一次,且对象只有一个
线程的api:
-static Thread currentThread();
获取当前的线程对象
-long getId();
获取线程的标识符
-String getName();
获取线程的名字
-int getPriority();
获取线程的优先级
优先级有10级 1-10(高)
-boolean isAlive();
获取当前线程是否为活动状态
-boolean isDaemon();
获取当前线程是否为守护线程
-boolean isInterrupted();
获取线程是否中断
-static void sleep(long 毫秒数);
指定的毫秒数内让当前正在执行的线程休眠(暂停执行)
此操作受操作系统计时器和调度程序精度和准确度的影响
Thread t=new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程的入口");
System.out.println("当前线程的对象-->"+Thread.currentThread());//当前线程的对象-->Thread[Thread-0,5,main]
System.out.println("当前线程的名称-->"+Thread.currentThread().getName());//当前线程的名称-->Thread-0
System.out.println("当前线程的id-->"+Thread.currentThread().getId());//当前线程的id-->10
System.out.println("当前线程的优先级-->"+Thread.currentThread().getPriority());//当前线程的优先级-->5
System.out.println("当前线程是否活着-->"+Thread.currentThread().isAlive());//当前线程是否活着-->true
System.out.println("当前线程是否为守护线程-->"+Thread.currentThread().isDaemon());//当前线程是否为守护线程-->false
System.out.println("当前线程是否中断-->"+Thread.currentThread().isInterrupted());//当前线程是否中断-->false
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程的出口");
}
});
t.start();
守护线程:
当进程中只剩下守护线程时,所有的守护线程强制终止
联合线程:
void join();
此方法用于等待当前线程结束
比如:
t1.join();//t1线程没有结束,当前线程不会开始
例:
public static void main(String[] args) {
//1.创建线程t1,用来下载图片
Thread t1=new Thread(new Runnable() {
@Override
public void run() {
System.out.println("t1:run begin");
for(int i=0;i<=20;i++){
System.out.println("t1:已下载图片"+i*5+"%");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("t1:run end 图片下载完毕");
}
});
t1.start();
//创建一个线程t2
Thread t2=new Thread(new Runnable() {
@Override
public void run() {
System.out.println("t2:等待图片下载完毕 begin");
try {
//t1线程没有结束,t2线程(当前线程)处于等待
//t2线程阻塞block或者挂起hangup
//等待t1线程结束,t2线程(当前线程)才能继续执行
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t2:显示图片(代码) end");
}
});
t2.start();
}
运行结果:
t1:run begin
t2:等待图片下载完毕 begin
t1:已下载图片0%
t1:已下载图片10%
t1:已下载图片20%
t1:已下载图片30%
t1:已下载图片40%
t1:已下载图片50%
t1:已下载图片60%
t1:已下载图片70%
t1:已下载图片80%
t1:已下载图片90%
t1:已下载图片100%
t1:run end 图片下载完毕
t2:显示图片(代码) end
线程的几个关键点:
1.线程何时启动,即线程对象.start();是有先后顺序的
有可能某个线程的启动要靠它的主线程是否启动
2.run方法的执行顺序(run并发执行),靠的是何时能start()和何时能获取到cpu
3.可能run并发执行着,需要注意线程之间的依存关系
当前线程是否执行完毕,是依赖与另一个线程是否执行完毕
run都执行,但结束是有顺序的(联合线程,join方法)
synchronized关键字:
同步,同步资源,同步锁
1.此关键字修饰在方法上
比如:
public synchronized void method(){
//代码块
}
当线程1调用method方法时,就会给method方法添加一个锁
如果方法不执行完毕,其他线程就不会执行此方法,线程排队等待
2.此关键字修饰在对象上
比如:
synchronized(某个对象){
//同步代码块
}
当线程1执行同步代码块时,就会给对象添加一个锁
如果代码不行完毕,其他线程就不会执行此方法,线程排队等待
3.此关键字修饰在类上
比如:
synchronized(类名.class){
//同步代码块
}
当线程1执行同步代码块时,就会给类添加一个锁
如果代码块不执行完毕,其他线程就不会执行此方法,线程排队等待