线程:
一个进程中同时运行多个线程,完成不同任务,叫多线程
并行:多个cpu同时执行多个任务
并发:一个cpu同时执行多个任务
每个线程之间都是竞争关系、谁抢到谁先执行【线程的优先级默认是5 最小值为1 最大10】
创建线程的三种方式:
【1】继承Thread类,实现多线程。缺点是,java中讲究的是单继承,如果使用此方法创建线程则无法继承其他类。
继承Thread类,使用多线程实现龟兔赛跑。
使用线程的第一种方式:A、继承Thread类 B、重写run() 方法
class RunnerThread extends Thread{
private String name;
public RunnerThread(String name) {
this.name = name;
}
@Override
public void run() {
for (int i = 0; i <= 100; i++) {
System.out.println(Thread.currentThread().getName()+" ");
}
}
}
主函数为:
public static void main(String[] args) throws Exception{
RunnerThread tuzi = new RunnerThread("兔子");
RunnerThread wugui = new RunnerThread("乌龟");
tuzi.start(); // 启动线程
wugui.start();
tuzi.setPriority(9); // 调整线程优先级
}
【2】实现Runnable接口:
实现Runnable接口的优点:当前类可继承其他类,多个线程之间共用一个对象
实现Runnable接口的缺点:无法拿到run方法的返回值、运行完的返回值
代码实现:
class RunnerThread2 implements Runnable{
@Override
public void run() {
// Thread.currentThread().getName() 此方法为获得线程的名字
System.out.println(Thread.currentThread().getName()+" ");
}
}
主函数内代码实现:体现 Runnable的多个线程共用一个对象
public static void main(String[] args) throws Exception{
RunnerThread2 thread2 = new RunnerThread2();
Thread tuzi = new Thread(thread2,"兔子");
Thread wugui = new Thread(thread2,"乌龟");
tuzi.start();
wugui.start();
Thread.currentThread().setPriority(1); // 给主线程设置优先级
}
【3】实现Callable接口--jdk1.5以后出的,功能最全
前两种皆为重写run方法;但无法获得其返回值
这种线程方式的特点:
{1} 可以接受方法返回值
{2}线程执行方法可抛出异常
代码实现:
class RunnerThread3 implements Callable<Integer> {
@Override
public Integer call() throws Exception {
// 随机获得十以内的整数
int i = new Random().nextInt(10);
System.out.println(Thread.currentThread().getName()+" ");
return i;
}
}
主函数实现:
public static void main(String[] args) throws Exception{
RunnerThread3 thread3 = new RunnerThread3();
// 需要存在一个转化值
FutureTask<Integer> f1 = new FutureTask<>(thread3);
FutureTask<Integer> f2 = new FutureTask<>(thread3);
// 线程定义
Thread th1 = new Thread(f1);
Thread th2 = new Thread(f2);
// 启动线程
th1.start();
th2.start();
// 接受线程的返回值
System.out.println(f1.get());
System.out.println(f2.get());
// 获得上方值即证明已经结束了并且返回了十以内的随机整数
}
另外还有两个常用的方法:
f1.cancel(true); 取消指定线程
f1.isDone(); 判断线程是否结束
线程通信:
线程通信在使用wait()的时候,if判断容易存在虚假唤醒的可能。一般来说会使用while判断来代替if判断,从而解决wait()虚假唤醒的情况。
1.用 等待 与 通知 来实现线程通信 次属于synchronized中的线程通信方法
{ wait() 等待 notify()/notifyAll() 通知 }
2.如果是Lock锁则需使用 {await() 等待 signal() 通知 需要两个对象才可以使用}
普通阻塞:sleep、join、Scanner、input、next()
同步阻塞:[锁池队列] 没有获取同步监视器的线程(synchronized)
等待阻塞:[阻塞队列] 被调用了wait() 后释放锁
Condition PC = lock.newCondition(); // 生产者的线程锁使用等待对象
Condition CC = lock.newCondition(); // 消费者线程使用的等待对象
生命周期:
使用join() 阻塞当前线程:
线程1.join();
线程2.join();
插入到主线程中相当于阻塞,使主线程最后执行(不是百分百最后)
使用sleep() 阻塞当前线程:
Thread.sleep(3000); 使主线程睡眠3秒,3秒后继续执行后面代码主线程睡眠后,自己后面不执行,但其他线程正常执行
使用yield礼让线程:
Thread.yield(); 线程礼让,使整个线程分布更加均匀
使用setDaemon()守护线程(伴随主线程一直运行,主线程停了 其他停):
线程1.setDaeman(true); 设1为住先储层的守护线程(主线程停止,线程1停止)