进程和线程
- 进程,是指计算机运行的一个程序,每个进程都有独自的代码和数据空间,进程间的切换会有很大的开销
- 线程,一个程序内部的多个控制流一个进程可以包括多个线程,线程之间切换开销很小
- 多进程,操作系统可以同时运行多个进程(程序)
- 多线程,在同一个程序中有多个线程执行
多线程实现的两种方式
继承Thread类,重写run()方法
public class 类名 extends Thread{
//重写run方法
@Override
public void run(){
//该线程实现的功能
}
}
开启线程:线程类对象名.start();
实现Runnable接口
public class 类名 implements Runnable{
//重写run()方法
@Override
public void run(){
//该线程实现的功能
}
}
开启线程:
- 先创建实现Runnable接口的类的对象
- 然后创建爱你Thread对象 Thread 对象名 = new Thread(Runnable对象);
- Thread对象调用start()方法
两种方式的比较
- 继承、接口(可以更好的扩展)
- 两种方式本质上都是调用了Thread的run方法
线程的生命周期
线程独对象从start开始到结束,期间存在不同的状态:
- 创建new
- 就绪状态,线程对象调用start方法后
- 运行状态,被线程调度器执行
- 阻塞状态,当运行中的线程产生阻塞事件时,进入阻塞状态,阻塞状态结束后,进入就绪状态
- 停止状态,线程运行完成
线程中的主要方法
- sleep(millis) ,Thread类的静态方法,接受一个以毫秒为单位的参数,表示让线程休眠millis毫秒
如:Tread.sleep(100);//让当前线程休眠100毫秒- join() ,在一个线程A中使用另一个线程对象B调用join()方法,表示线程A等待另一个线程B结束后再继续执行A线程
- yield(),让出cpu,进入就绪队列
- isAlive(),判断线程是否存活
- wait(),让该对象上的当前线程进入等待,直到其他线程调用此对象的notify()方法或notifyAll()方法
- notify(),唤醒在此对象监视器上等待的单个线程
- notifyAll(),唤醒在次对象监视器上等待的所有线程
线程的优先级
- 就绪状态的线程,如果有多个,线程调度器在选择就绪状态的线程时,优先选择优先级高的运行
- java线程优先级公有十级1~10,10最高,1最低,默认为优先级为5
Thread.MAX_PRIORITY //10
Thread.NOMAL_PRIORITY //5
Thread.MIN_PRIORITY //1
使用getPriority()方法获取优先级,setPriority()方法设置优先级
线程的同步
如果涉及到多个线程操作同一个资源,会产生问题。
同步是指多个线程同时操作同一个资源时,需要排队操作,保证同一个时间点只有一个线程操作这个资源。
至少有一个线程修改这个资源时,需要线程同步。如果多个线程只进行读取资源,则不需要线程同步。
线程同步在java中使用关键字synchronize,主要分为两种形式:
- synchronize修饰一段代码块
- 使用synchronize修饰对同一资源操作的代码块,需要传入一个对象,可以传入this代表当前对象
- synchronize(对象){//代码块}
- 优点:可以只选择需要同步的少量代码进行加锁,释放锁速度快,可以获取其他对象的锁
- 缺点:不易于查看哪些方法是加锁的
- synchronize修饰一个方法
表示同一时刻只能有一个线程来调用该方法,其他线程在上一个线程调用完成之前不能调用相同对象的此方法- 优点:可以明显地知道哪些方法是同步的
- 缺点:如果方法中有其他的不需要同步的代码,仍然需要执行完整个方法后才会释放同步锁,且只能获取相同对象的锁
死锁状态
两个线程之间互相等待对方的锁,造成死锁状态
线程锁示例
实现奇数。偶数交替输出
Thread1类,实现奇数的输出:
public class Thread1 implements Runnable{
private Object obj;
public Thread1(Object obj) {
this.obj = obj;
}
@Override
public void run() {
synchronized (obj) {//获取相同对象的锁
//输出奇数
for(int i = 1;i <= 100;i+=2) {
System.out.println("Thread1:"+i);
obj.notify();//唤醒该对象上的其他线程
try {
obj.wait();//本线程进入等待
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
Thread2类,实现偶数的输出:
public class Thread2 implements Runnable{
private Object obj;
public Thread2(Object obj) {
this.obj = obj;
}
@Override
public void run() {
synchronized (obj) {//获取相同对象的锁
//输出偶数
for(int i = 2;i <= 100;i+=2) {
System.out.println("Thread2:"+i);
obj.notify();//唤醒该对象上的其他线程
try {
obj.wait();//本线程进入等待
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
测试类:
public class Test1 {
public static void main(String[] args) {
Object obj = new Object();
Thread1 run1 = new Thread1(obj);//传入相同的对象
Thread2 run2 = new Thread2(obj);
Thread t1 = new Thread(run1);
Thread t2 = new Thread(run2);
t1.start();
t2.start();
}
}