自定义线程
实现方式
- 继承Thread类
- 实现Runnable 接口
继承Thread 类
- 继承Thread后,要重写run 方法
- public void run 方法体 为该线程要执行的任务
- 启动线程的方法为start() ,不是调用run()
- 调用run方法不能开启新的线程,只是普通的函数调用
- 线程的生命周期类只能被启动一次
public class xiancheng2 { public static void main(String[] args) { //创建对象 Myrun run1 = new Myrun(); //创建线程对象 Thread runTd = new Thread( run1 ); // 开启线程 runTd.start(); run1.say(); } } class Myrun extends Thread{ @Override public void run() { System.out.println("新的线程"); } public void say() { System.out.println( "美好的一天" ); } }
常用API
String getName() | 返回该线程的名称。 |
long getId() | 返回该线程的标识符。 |
int getPriority() | 返回线程的优先级。 |
Thread.State getState() | 返回该线程的状态。 |
join() | 等待该线程终止。 |
join( long millis ) | 等待该线程终止的时间最长为 millis 毫秒。 |
static void sleep(long millis ) | 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)。 |
void start() | |
void interrupt() | 中断线程。 |
static boolean interrupted() | 测试当前线程是否已经中断。 |
boolean isDaemon() | 测试该线程是否为守护线程。 |
实现Runnable 接口
方法与继承Tread 类似即:
- 继承Runnable 接口,实现run 方法
- 创建线程对象 , 开启线程
差异
- 通过接口的方式,更加灵活(Java是单继承)
- 继承的方式更加简单。(使用较少)
线程状态
- 一个线程一般要经历5个状态
- 新建状态
- 准备状态
- 运行状态
- 等待/阻塞状态
- 睡眠 : 调用sleep()
- 阻塞 :
- 挂起 : 调用suspend 挂起,resume()解除挂起 ( 不建议使用)
- 等待 : 调用 wait()
- 死亡状态
线程的使用
睡眠
调用sleep方法可以让线程睡眠指定的时间后再苏醒进入准备状态,
public static void sleep( long millis) throw InterruptedException
public static void sleep( long millis , int nanos) throw InterruptedException
public class xiancheng2 { public static void main(String[] args) throws InterruptedException{ //创建对象 Myrun run1 = new Myrun(); //创建线程对象 Thread runTd = new Thread( run1 ); Thread runTd2 = new Thread( run1 ); // 开启线程 runTd.start(); //使主线程睡眠100ms Thread.sleep(100); System.out.println( "美好的一天" ); } } class Myrun implements Runnable{ @Override public void run() { System.out.println("新的线程"); try { // 使该线程睡眠100ms Thread.sleep(100); } catch (Exception e) { // TODO: handle exception } } }
线程的优先级
- Java中线程的优先级用1~10之间的整数表示。值越大,优先级越高。默认为5
不适合对线程进行细节调节
主线程的优先级默认为5。子线程优先级初始值与父线程相同。
改变优先级:(不能精确)
public final void setPriority( int newPriority )
public class xiancheng2 { public static void main(String[] args) { //创建对象 Myrun run1 = new Myrun(1); Myrun run2 = new Myrun(2); //创建线程对象 Thread runTd1 = new Thread( run1 ); Thread runTd2 = new Thread( run2 ); //设置优先级 runTd2.setPriority( Thread.MIN_PRIORITY );//最高的优先级 runTd1.setPriority( Thread.MAX_PRIORITY );//最低的优先级 //开启线程 runTd2.start(); runTd1.start(); } } class Myrun implements Runnable{ private int id ; public Myrun(int id) { this.id = id; } @Override public void run() { System.out.println("新的线程"+ this.id); } }
线程的让步
- 分类
- 线程只是让出当前的CPU资源,具体将CPU让给谁不能确定 (无保障)
- 线程将给指定的线程让步,指定的线程没有完成,其绝不恢复执行 (线程合并--有保障)
yield方法
使当前正在运行的线程让出CPU,回到准备状态。(无保障)
pubic static void yield()
join方法
调用join方法的线程将执行完,后再恢复其他线程执行
public final void join( ) throw InterruptedException
public final void join( long millis) throw InterruptedException
public final void join( long millis ,int nanos ) throw InterruptedException
public class xiancheng2 { public static void main(String[] args) throws InterruptedException{ Thread run1 = new Myrun("先"); Thread run2 = new Myrun("后"); run2.start(); run2.join(); //run2线程将执行完后,在恢复其他线程。 run1.start(); for (int i = 0; i < 50; i++) { System.out.print(6); } } } class Myrun extends Thread{ private String id ; public Myrun(String id) { this.id = id; } @Override public void run() { try { } catch (Exception e) { // TODO: handle exception } for(int i=100 ;i>0;i--) { System.out.print(this.id); } } }
注意(有参)
如果A线程中掉用B线程的join(10),则表示A线程会等待B线程执行10毫秒,10毫秒过后,A、B线程并行执行。 需要注意的是,jdk规定,join(0)的意思不是A线程等待B线程0秒,而是A线程等待B线程无限时间,直到B线程执行完毕,即join(0)等价于join()。 摘自:https://www.cnblogs.com/ldq2016/p/9045551.html
线程守护
- 在后台运行的线程(内存管理,线程调度...) 称之为守护线程
开发守护线程
public final void setDaemon( boolean on ) // on表示是否设置为守护线程(fal se:普通线程)
- java中 : 但前台线程(普通线程)都运行结束后,程序退出
- 与回台程序是否运行完无关。
- java中 : 但前台线程(普通线程)都运行结束后,程序退出
同步线程
同步方法
同步方法是指用synchronized修饰的方法
synchronized 方法名 ([参数列表])[throw 异常]{
}
- 静态的同步方法的锁对象为 : 当前的class的对象
- 非静态的同步方法的锁对象为 :this
- 当线程获得锁锁后进入睡眠或让步,将带着锁一起睡眠,让步。
- 同步方法退出后,锁将被释放,等待其他的线程可以获取锁。
- 同步将会降低多线程的并发性。
public class tridet { public static void main(String[] args) { Ticket tck = new Ticket(); Thread t2 = new Thread(tck,"window1"); Thread t1 = new Thread(tck,"window2"); Thread t3 = new Thread(tck,"window3"); System.out.println( "tck: " + tck ); t1.start(); t2.start(); t3.start(); } } class Ticket implements Runnable{ private int TicketNum = 100; public void run() { while( this.TicketNum>0 ) { this.buy(); } } public synchronized void buy() { System.out.println( this ); // this ==> tck(锁对象) if(this.TicketNum-->0) System.out.println(Thread.currentThread().getName() + "买出一张票,还剩:" + this.TicketNum ); } }
同步调度方法
final void wait() | 使某个线程进入等待状态。直到别的线程调用notify或notifyAll方法将其唤醒 |
final void wait(long timeout) | timeout 毫秒数,使某个线程进入等待状态,直至达到等待时间,或将其唤醒为止。 |
final void notify() | 唤醒等待池中的某一个线程(没有保障,不能确定唤醒哪一个线程) |
final void notifyAll() | 唤醒等待池中的所有线程 |
同步语句块
synchronized (锁对象){ }
- 锁对象要唯一
- 锁对象就如同一个保管钥匙的人,要使保证同步那么就要保证只有当一个线程执行完了同步语句块后(归还钥匙)其他的线程才能进入同步语句块,所有保管钥匙的人要唯一(钥匙只有一把)。
public class tridet { public static void main(String[] args) { // TODO Auto-generated method stub Thread t2 = new Ticket("window2"); Thread t1 = new Ticket("window1"); Thread t3 = new Ticket("window3"); t1.start(); t2.start(); t3.start(); } } class Ticket extends Thread{ private static int TicketNum = 10; private static Object look = new Object(); // 锁对象(唯一) public void run() { while( this.TicketNum > 0 ) { synchronized (look) { if(this.TicketNum--<=0) break; System.out.println(getName() + "买出一张票,还剩:" + this.TicketNum ); } } } public Ticket(String name) { super(name); } }
public class tridet { public static void main(String[] args) { Ticket tck = new Ticket(); Thread t2 = new Thread(tck,"window1"); Thread t1 = new Thread(tck,"window2"); Thread t3 = new Thread(tck,"window3"); t1.start(); t2.start(); t3.start(); } } class Ticket implements Runnable{ private int TicketNum = 100; public void run() { while( this.TicketNum > 0 ) { synchronized (this) { //锁对象为this , 即:tck对象(唯一) if(this.TicketNum--<=0) break; System.out.println(Thread.currentThread().getName() + "买出一张票,还剩:" + this.TicketNum ); } } } }
死锁
- 相互等待对方释放资源的对象的 锁。
public class shisuo { public static void main(String[] args) { // TODO Auto-generated method stub Object oj1 = new Object(); Object oj2 = new Object(); boy b1 = new boy( oj1 , oj2 ); girl g1 = new girl( oj1 , oj2 ); Thread thread1 = new Thread(b1,"boy"); Thread thread2 = new Thread(g1,"boy"); thread1.start(); thread2.start(); } } class boy implements Runnable { private Object look1, look2; public boy(Object look1, Object look2) { super(); this.look1 = look1; this.look2 = look2; } public void run() { synchronized (look1) { System.out.println("body"); synchronized (look2) { System.out.println("body2"); } } } } class girl implements Runnable { private Object look1, look2; public girl(Object look1, Object look2) { super(); this.look1 = look1; this.look2 = look2; } public void run() { synchronized (look2) { System.out.println("girl"); synchronized (look1) { System.out.println("girl2"); } } } }
volatile 关键字
作用:被其修饰的成员变量不允许一个线程对其操作过程中,其他线程插入操作。
- 该关键字只允许修饰成员变量 , 不能修饰局部变量。
- 局部变量不可能同时被两个线程
来源:https://www.cnblogs.com/zoukun/p/12275832.html