长沙网站设计优秀柚v米科技,专业深圳网站定制开发,诸城做网站收费,wordpress 导航栏登录Thread 线程启动线程第一种创建线程线程的第二种创建方式使用匿名内部类完成线程的两种创建 Thread API线程的优先级线程提供的静态方法守护线程用户线程和守护线程的区别体现在进程结束时 多线并发安全问题同步块 线程
启动线程
启动线程:调用线程的start方法,而不是直接调用… Thread 线程启动线程第一种创建线程线程的第二种创建方式使用匿名内部类完成线程的两种创建 Thread API线程的优先级线程提供的静态方法守护线程用户线程和守护线程的区别体现在进程结束时 多线并发安全问题同步块 线程
启动线程
启动线程:调用线程的start方法,而不是直接调用run方法 当线程调用start方法后就会纳入到线程调度器中统一调度.第一次获取时间片后会开始自动执行它的run方法
第一种创建线程
class MyThread1 extends Thread{public void run(){for (int i 0; i 1000; i) {System.out.println(你是谁啊?);}}
}
class MyThread2 extends Thread{public void run(){for (int i 0; i 1000; i) {System.out.println(开门,查水表的!);}}
}优点:
结构简单,便于使用匿名内部类形式创建
缺点: 存在继承冲突问题 当我们定义的类需要是一个线程时,我们要继承Thread,但是同时我们还需要继承另一个类来复用方法, 由于java是单继承的,这会导致出现了继承冲突问题 线程与线程要执行的任务存在了必然的耦合关系 定义一个线程的同时重写了run方法来定义线程的任务,这会导致线程和任务绑定在一起,没有办法最大程度的重用线程
线程的第二种创建方式
class MyRunnable1 implements Runnable{public void run(){for (int i 0; i 1000; i) {System.out.println(你是谁啊?);}}
}
class MyRunnable2 implements Runnable{public void run(){for (int i 0; i 1000; i) {System.out.println(开门,查水表的!);}}
}使用匿名内部类完成线程的两种创建
Runnable r2 () - {for (int i 0; i 1000; i) {System.out.println(开门!查水表!);}
};
Thread t2 new Thread(r2);Thread t1 new Thread(() - {for (int i 0; i 1000; i) {System.out.println(你是谁啊?);}
});Thread API
线程的优先级
线程有10个优先级,分别用整数1-10表示 1为最低优先级,10为最高优先级,5为默认值 Thread定义了上下限的常量
Thread.MAX_PRIORITY为最高优先级,对应整数10Thread.MIN_PRIORITY为最低优先级,对应整数1Thread.NORM_PRIORITY为默认优先级,对应整数5
优先级越高的线程获取时间片的次数越多,线程调用start方法后就纳入到线程调度器中被统一管理,线程没有主动索取时间片的能力,只能被动被分配 public static void main(String[] args) {Thread min new Thread(){public void run(){for (int i 0; i 10000; i) {System.out.println(min);}}};Thread max new Thread(){public void run(){for (int i 0; i 10000; i) {System.out.println(max);}}};Thread norm new Thread(){public void run(){for (int i 0; i 10000; i) {System.out.println(nor);}}};min.setPriority(Thread.MIN_PRIORITY);max.setPriority(Thread.MAX_PRIORITY);min.start();norm.start();max.start();}线程提供的静态方法
static void sleep(long millis) 该方法可以让执行该方法的线程主动进入阻塞状态指定毫秒,超时后线程会主动回到RUNNABLE状态再次开始并发
public static void main(String[] args) {System.out.println(程序开始了);try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(程序结束了);}sleep方法要求必须处理中断异常InterruptedException 当一个线程调用sleep方法处于睡眠阻塞的过程中,此时该线程的interrupt方法被调用,那么就会立即中断其睡眠阻塞,此时sleep方法会立即抛出中断异常
public static void main(String[] args) {Thread lin new Thread(林永健){public void run(){System.out.println(getName():刚美完容,睡一会吧...);try {Thread.sleep(300000000);} catch (InterruptedException e) {System.out.println(getName():干嘛呢!干嘛呢!干嘛呢!都破了相了!);}System.out.println(getName():醒了);}};Thread huang new Thread(黄宏){public void run(){System.out.println(getName():大锤80!小锤40!开始砸墙!);for(int i0;i5;i){System.out.println(getName():80!);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(咣当!!);System.out.println(getName():大哥!搞定!);lin.interrupt();//中断lin线程的睡眠阻塞}};lin.start();huang.start();}守护线程
我们正常创建出来的线程称为用户线程或前台线程。守护线程是通过用户线程调用setDaemon(true)在启动前设置转变而来的.守护线程一般也可以称为后台线程
用户线程和守护线程的区别体现在进程结束时
当进程中所有用户线程都结束时,进程就会结束,结束前会无差别杀死所有还在运行的守护线程 GC就是运行在守护线程上的
public static void main(String[] args) {Thread rose new Thread(){public void run(){for(int i0;i5;i){System.out.println(rose:let me go!);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(rose:啊啊啊啊啊AAAAAAaaaaaaa....);System.out.println(pia!);}};Thread jack new Thread(){public void run(){while(true){System.out.println(jack:you jump!i jump!);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}};rose.start();jack.setDaemon(true);//设置为守护线程,必须在线程启动前进行设置否则会抛出异常jack.start();//while (true);//如果main方法不结束,jack是不会结束的}//main方法执行完毕,主线程就结束了多线并发安全问题
当多个线程并发操作同一临界资源,由于线程切换时机不确定,导致执行顺序出现混乱从而引起不良后果
临界资源: 操作该资源的完整过程同一时刻只能被单个线程进行
/*** 使用当前类理解并发安全问题的产生* 以银行取钱业务为例,如果多个人从同一个账号上取钱所出现的并发全问题.*/
public class Bank {private int account 20000;public boolean getMoney(int money) {int account getAccount();if (account money) {//余额取款金额account account - money;Thread.yield(); //主动放弃时间片目的模拟执行到这里时CPU时间片用完了saveAccount(account); //重新记账return true; //取款成功}return false; //取款失败}public void saveAccount(int account) {this.account account;}public int getAccount() {return account;}}public static boolean success1 false;//表示t1线程是否取款成功
public static boolean success2 false;//表示t2线程是否取款成功
public static int sum 0;//记录一共测试了几轮public static void main(String[] args) {//实例化一个BankBank bank new Bank();while(true) {sum;Thread t1 new Thread() {public void run() {success1 bank.getMoney(20000);}};Thread t2 new Thread() {public void run() {success2 bank.getMoney(20000);}};t1.start();t2.start();try {/*当主线程执行完上述启动t1和t2的代码后,让主线程阻塞5毫秒(目的是等待t1和t2执行完毕)*/Thread.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}if(success1success2){//都为true则说明同时取款成功System.out.println(漏洞产生,两个线程同时取款成功!总共尝试了sum次);break;}else{bank.saveAccount(20000);//将银行账号重新存入20000}}}同步块
Java同步块是一种同步机制它可以确保在同一时刻只有一个线程可以执行特定的代码块或方法。这种机制可以防止多个线程同时修改同一数据从而防止出现竞态条件。
同步块可以更准确的控制需要多个线程同步执行的代码片段
同步块要求指定同步监视器对象,该对象选取有两个必要的要求:
必须是一个引用类型对象多个需要同步执行该代码片段的线程看到的必须是同一个同步监视器对象
合适的锁对象选取: 在具有并发安全问题时,多个线程看到的是同一个对象,不存在并发安全问题时看到的则不是同一个对象. 选取原则: 通常选取临界资源作为同步监视器对象,即:抢谁就锁谁 语法:
synchronized(同步监视器对象){ 需要多个线程同步执行的代码片段 }
有效的缩小同步范围可以在保证并发安全的前提下提高并发效率
public static void main(String[] args) {Shop shopA new Shop();Shop shopB new Shop();Thread t1 new Thread(Tom){public void run(){shopA.buy();}};Thread t2 new Thread(Jerry){public void run(){shopB.buy();}};t1.start();t2.start();}
}
class Shop{/*在方法上直接使用synchronized,那么同步监视器对象不可选,只能是this*/
// public synchronized void buy(){public void buy(){try {Thread t Thread.currentThread();//获取运行buy方法的线程System.out.println(t.getName():正在挑衣服...);Thread.sleep(5000);synchronized (this) {System.out.println(t.getName() :正在试衣服...);Thread.sleep(5000);}System.out.println(t.getName():结账离开);} catch (InterruptedException e) {e.printStackTrace();}}