多进程与多线程的区别
每个进程拥有自己的一整套变量,而线程则共享数据。共享变量使线程之间的通信比进程之间的通信更有效,更容易。在有些操作系统中,与进程相比,线程更“轻量级”,创建、撤销一个线程的开销远比进程开销小。
创建线程的方式
第一种方法是构建一个Thread类的子类并重写run方法,这种方法是不推荐的,应该将并行运行任务与运行机制解耦。
class MyThread extends Thread{
@Override
public void run(){
...}
}
MyThread t=new MyThread();
第二种方法是实现Runnable接口,这种方法也更加灵活,当一个类继承了其他类时也可以通过实现该接口定义为线程,第一种方法的话由于不能多继承因此继承了其他类就不能定义为线程了。
class MyThread implements Runnable{
@Override
public void run(){
...}
}
MyThread r=new MyThread();
//将实现了Runnable接口的类实例作为参数传递创建线程
Thread t=new Thread(r);
//也可通过匿名内部类创建线程
Thread t=new Thread(new Runnable() {
@Override
public void run() {
...
}
});
//或者用lambda表达式
Thread t=new Thread(()->{
...
});
以上创建线程的实际效果都是一样的
线程状态
新创建(New) :用new操作符创建一个新线程
可运行(Runnable):调用start方法后线程处于runnable,可能运行也可能没有
被阻塞(Blocked):内部锁获取失败将被阻塞
等待(Waiting):等待其他线程通知 wait/join等
计时等待(Time Waiting):带超时参数的等待 sleep/wait/join等
终止(Terminated):run方法正常推出/未捕获异常终止了run方法
线程属性
线程优先级 可以用setPriority(int n)设置线程的优先级
在Linux中的JVM里线程优先级相同
yield方法是一个静态方法,它可以使当前线程处于让步状态,如果其他线程的优先级大于等于它,就优先调度。类似欺软怕硬。。
守护线程:调用setDaemon(true)将线程转换为守护线程,唯一的目的是为其他线程服务,只剩守护线程时JVM就退出了。setDaemon方法必须在线程启动前调用
同步
两个或以上线程需要共享对同一数据的存取,这样可能会发发生一些错误
举个例子
一个银行类
public class Bank {
private final double[] accounts;
public Bank(int n,double initBalance){
accounts=new double[n];
Arrays.fill(accounts,initBalance);
}
public void transfer(int from,int to,double amount) throws InterruptedException {
while (true){
System.out.print("当前线程:" + Thread.currentThread());
accounts[from] -= amount;
System.out.