1、线程的状态
休眠方法:
public static void sleep(long millis)
放弃方法:放弃对时间片的使用
public static void yield()
优先级方法、守护线程方法:
守护线程的作用:
JVM 程序在什么情况下能够正常退出?
答:当 JVM 中不存在任何一个正在运行的非守护线程时,则 JVM 进程即会退出。
如果 JVM 中没有一个正在运行的非守护线程,这个时候,JVM 会退出。换句话说,守护线程拥有自动结束自己生命周期的特性,而非守护线程不具备这个特点。
2、多线程特点以及创建方式
多线程的特点是抢占式
cpu时间片安排线程的访问时间
创建线程的方式
继承Thread方法重写run()方法
1.用this.getId()和this.getName()获取线程的id和名称
2.用Thread.currentThread()获取当前线程 //如果当前线程没有继承Thread类的时候用
3.修改线程名称:调用setName方法;利用构造方法 super(name);
public class ThreadTest extends Thread {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "线程方法被调用了");
}
public static void main(String[] args) {
ThreadTest threadTest = new ThreadTest();
threadTest.start();
}
}
第二种创建线程的方法:
继承Runnable接口,重写run方法//这个类是一个run方法的实现类,在main方法中创建Thread线程对象时把该方法类传入Thread中可以创建子线程
可以使用匿名内部类的方法直接进行线程创建
public class TestRunnable implements Runnable {
@Override
public void run() {
System.out.println("实现了run方法");
}
}
public static void main(String[] args) {
Thread thread = new Thread(new TestRunnable());
thread.start();
}
实现Callable接口,重写call方法,
- 可以定义返回值
- 可以抛出异常
public class TestCallable implements Callable<Boolean> {
@Override
public Boolean call() throws Exception {
System.out.println("创建成功");
return true;
}
public static void main(String[] args) {
TestCallable callable = new TestCallable();
//创建执行服务
ExecutorService service = Executors.newFixedThreadPool(1);
//提交执行
Future<Boolean> result = service.submit(callable);
boolean isTrue = result.get();
service.shutdownNow();
}
}
但是,Runnable缺少的一项功能是,当线程终止时(即run()完成时),我们无法使线程返回结果。为了支持此功能,Java中提供了Callable接口。
为了实现Runnable,需要实现不返回任何内容的run()方法,而对于Callable,需要实现在完成时返回结果的call()方法。请注意,不能使用Callable创建线程,只能使用Runnable创建线程。
另一个区别是call()方法可以引发异常,而run()则不能。
为实现Callable而必须重写call方法。
3、如何保证线程安全性
1.
同步代码块
synchronized{
}
注意线程中的循环会一直执行,但是会根据时间片分配的时间一直执行,不会从头开始循环
2.
当使用静态方法时候锁是(类.class)也就是当前类的类型,非静态方法锁是this
3. 死锁
4、线程的同步异步
Lock锁
lock锁和synchronized对比
Lock是显示锁(手动开启和关闭,别忘记关闭锁) synchronized是隐式锁,出了作用域自动释放
Lock只有代码块锁,synchronized有代码块锁和方法锁
使用lock锁,JVM将花费较少的时间来调度线程,性能更好,并且具有更好的扩展性(提供更多的子类)
优先使用顺序
Lock > 同步代码块 > 同步方法
public class TestLock {
public static void main(String[] args) {
TestLock2 testLock2 = new TestLock2();
new Thread(testLock2).start();
new Thread(testLock2).start();
new Thread(testLock2).start();
}
}
class TestLock2 implements Runnable {
int ticketNums = 10;
//定义Lock锁
private ReentrantLock reentrantLock = new ReentrantLock();
@Override
public void run() {
while (true) {
try {
reentrantLock.lock(); //加锁
if(ticketNums > 0 ){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "购买了第" + ticketNums-- + "张票");
} else {
break;
}
} finally {
//解锁
reentrantLock.unlock();
}
}
}
}
5、读写锁、互斥锁
读写锁的效率比互斥锁高很多
读写锁关系:写和写、写和读互斥、读和读不互斥
互斥锁全部都互斥
3、使用线程池
- 背景: 经常创建和销毁,使用量特别大的资源,比如并发情况下的线程,对性能影响很大
- 思路: 提前创建好多个线程,放入线程池中,使用时直接获取,使用完毕放回池中,可以避免频繁的创建销毁,实现重复利用,类似生活中的工共交通工具
- 好处
- 提高了响应速度(减少了创建新线程的时间)
- 降低资源消耗(重复利用线程池中线程,不需要每次都创建)
- 便于线程管理(…)
- corePoolSize: 核心池的大小
- maximumPoolSize: 最大线程数
- keepAliveTime: 线程没有任务时最多保持多长时间后会终止
blic class Main {
public static void main(String[] args) {
TV tv = new TV();
new Watcher(tv).start();
new Player(tv).start();
}
}