一、创建线程的三种方式
1.继承Thread类重写run方法
run方法里面写要执行的代码块
public class MyThread extends Thread{ @Override public void run() { super.run(); } }
2.实现Runnable接口 Runnble只是一个任务 实现后 必须要让Thread来执行 创建Runnable实现类对象 把对象放在new Runnbale(参数) 调用start方法执行 Runnble相当于一个任务 而Thread相当于执行它
public class MyThread1 implements Runnable{ @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(i); } } } public class MyThread { public static void main(String[] args) { MyThread1 myThread1 = new MyThread1(); Thread thread = new Thread(myThread1); thread.start(); } }
匿名Runnbale类 如果只使用一次 可以使用匿名内部类在Thread里
public class MyThread { public static void main(String[] args) { MyThread1 myThread1 = new MyThread1(); Thread thread = new Thread(myThread1); thread.start(); } }
3.实现Callable接口 关于实现Callable暂时不讲
二、获取线程和修改线程名称
获取线程ID和线程名称
1.在Thread的子类调用this.getId()或this.getName()来获取ID和线程名称 但是这种方式缺点是:必须要继承Thread才能调用
2.使用Thread.currenThread().getId和Thread.currenThread().getName()来获取ID和名称 推荐使用这种方式 不用继承Thread 直接可以使用
修改线程名称
1.调用线程队形的setName()方法
2.使用线程子类构造方法赋值
public class MyThread { public static void main(String[] args) { Thread thread = new Thread("我的线程1"); thread.setName("我的线程1"); } }
3、抢占式调度
Java是抢占式调度 当多个线程执行的时候 每个线程都会去抢占CPU 而CPU会把时间平均分给每个线程时间(时间片) 当线程的时间片使用完后 又把CPU使用还回去 又给其他线程执行
4、Thread常见方法
常见方法
*休眠:
public static void sleep(long millis) 休眠程序 1000毫秒 == 1秒
*放弃
public static void yield()
当前线程主动放弃时间片 回到就绪状态 竞争下一次时间片
*加入:
public final void join()
允许其他线程加入到当前线程中
*优先级
线程对象.setPriority()
线程优先级1-10 默认为5 优先级越高 表示获取CPU机会越多
*守护线程
线程对象setDaemon(true)设置为守护线程
线程有两类:用户线程(前台线程)、守护线程(后台线程)
如果程序中所有前台线程都执行完毕了 后台线程会自动结束
垃圾回收器线程属于守护线程
5、同步线程
为什么要同步?
当多个线程执行一个类的时候 当线程抢到cpu执行 还没运行完 就被其他线程抢走了 这样多个线程对一个类的时候 数据会不统一 所以多个线程必须同步 使用synchronized
同步方式(1)
同步代码块:(把当前线程执行后 才可以解锁 执行其他线程)
Synchronized(临界资源对象){ //对临界资源对象加锁
//代码(原子操作)
public class MyThread1 implements Runnable{ @Override public void run() { synchronized (this){ for (int i = 0; i < 10; i++) { System.out.println(i); } } } }
synchronize()参数里面放同步的参数 没有使用this可以
同步方式(2):
同步方法:synchronized 返回值类型 方法名称(形参列表0){ //对当前对象 (thsi)加锁
//代码(原子操作)
}
注:
只有拥有对象相互斥锁标记的线程 才能进入该对象加锁的同步方法中
线程退出同步方法时 会释放相应的互斥锁标记
6、线程通信
等待
public final void wait()
public final void wait(long timeout)
必须在对obj加索的同步代码块中 在一个线程中 调用obj.wait()时 此线程会释放
其拥有的锁标记 同时此线程阻塞在o的等待队列中 释放锁 进入等待队列
通知
public final void notify()
public final void notifyAll()