并行:一群人分别在不同的售票窗口买票(排成多列)
并发:一群人在一个售票窗口排队买票(排成一列)
线程:进程中的一个执行任务(控制单元),负责当前进程中程序的执行。多个线程可共享同一个数据,共用所在进程的那一块内存空间。
进程:一个在内存中运行的应用程序。每个进程都有自己独立的一块内存空间。windows 中一个 运行的 .exe 就是一个进程
一个程序下至少有一个进程,一个进程下至少有一个线程,一个进程下也可以有多个线程来增加程序的执行速度。
start()
调用 start() 时处于就绪状态,当时间片分配到本线程时,才从就绪状态变为运行状态
start() 方法用于启动线程
run() 方法只是用于执行线程的运行时代码。
ThreadRunnable
run() 方法Callable
call() 方法继承 Thread
public class MyThread extends Thread{
@Override
public void run() {
System.out.println("执行线程...");
}
public static void main(String[] args) {
Thread t = new MyThread();
t.start();
}
}
实现 Runnable
public class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println("执行线程任务...");
}
public static void main(String[] args) {
Runnable r = new MyRunnable();
Thread t = new Thread(r);
t.start();
// new Thread(r).start(); // 还可以这样写
}
}
实现 Callable
public class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("执行线程...");
return 10;
}
public static void main(String[] args) {
Callable c = new MyCallable();
FutureTask<Integer> f = new FutureTask(c);
Thread t = new Thread(f,"有返回值的线程对象名字");
t.start();
try {
System.out.println("线程的返回值 : " + f.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
继承 Thread 比较有局限性,因为 Java 中是单一继承,多实现。我们一旦继承了 Thread 类就没办法继承其他父类了,这样不利于代码开发,而且数据就会变成线程所独享的了;
而如果实现了 Runnable 接口,不仅可以继续继承其他的类,而且可以把数据变成所有线程共享的,将线程任务放到线程中运行即可。
实现 Callable 可以通过 FutureTask 对象 get() 方法获取执行线程任务结束后的返回值,但是相对于 Thread 来讲,编程较为复杂。
都是暂停的状态,都会让出CPU时间片,
sleep() 是线程 Thread 的静态方法wait() 是 Object 类的方法sleep() 不释放锁,没有释放被占用的这个资源,其他线程不能使用这个资源wait() 释放锁,需要 notify 或者 notifyAll 才能唤醒当前线程sleep() 暂停执行wait() 通常被用于线程间的通信sleep() 任何地方都能使用wait() 只能用在同步方法或者同步块中锁是为了实现共享资源的同步,防止多线程并发情况(多线程可能对同一数据同时操作,导致数据出现异常),所以有了锁机制(synchronized,Lock);
当线程 A 持有独占锁 a,并尝试去获取独占锁 b 的同时,线程 B 持有独占锁 b,并尝试获取独占锁 a 的情况下,就会发生 AB 两个线程由于互相持有对方需要的锁,而发生的阻塞现象,我们称为死锁。
(1)持有多个锁的话,锁的顺序要一致
(2)尽量避免锁的嵌套
(3)持有锁的方法尽量不要引用外部对象,可能外部对象也持有你的锁,会造成死锁