国外电商网站有哪些,网站开发 荣誉资质,移动端网站的重要性,小程序注册完成后如何制作文章目录 #xff08;1#xff09;练习题1#xff08;2#xff09;练习题2#xff08;3#xff09;练习题3 现在咱们线程一共说了这么几件事情#xff0c;如下#xff1a; 具体文章见专栏。 接下来看几个练习题吧。
#xff08;1#xff09;练习题1
#x1f30b;题… 文章目录 1练习题12练习题23练习题3 现在咱们线程一共说了这么几件事情如下 具体文章见专栏。 接下来看几个练习题吧。
1练习题1
题目描述
【新年倒计时】
模拟新年倒计时每隔1秒输出一个数字依次输出10,9,8…1最后输出新年快乐
分析
题目中没有说要造分线程那我们可以直接放到主线程里面也是可以的。
直接写一个for循环遍历即可如下
public class HappyNewYear {public static void main(String[] args) {for (int i 10; i 1 ; i--) {System.out.println(i);}}
}然后sleep让它一秒钟输出一下。如下 记得处理一下异常 这里只能用try-catch处理因为sleep抛出的方法是编译时异常而且父类没有抛出不能使用throws的方式。 代码
package yuyi03;/*** ClassName: HappyNewYear* Package: yuyi03* Description:* 模拟新年倒计时每隔1秒输出一个数字依次输出10,9,8......1最后输出新年快乐* Author 雨翼轻尘* Create 2024/1/30 0030 13:03*/
public class HappyNewYear {public static void main(String[] args) {for (int i 10; i 0 ; i--) {try {Thread.sleep(1000); //睡1s} catch (InterruptedException e) {e.printStackTrace();}if(i0){System.out.println(i);}else {System.out.println(HappyNewYear!);}}}
}输出结果 2练习题2
题目描述
关于Thread.sleep()方法的一个面试题
如下的代码中sleep()执行后到底是哪个线程进入阻塞状态了呢
代码
package yuyi03;/*** ClassName: ThreadTest* Package: yuyi03* Description:* 如下的代码中sleep()执行后到底是哪个线程进入阻塞状态了呢* Author 雨翼轻尘* Create 2024/1/30 0030 13:16*/public class ThreadTest {public static void main(String[] args) {// 创建线程对象MyThread t new MyThread();t.setName(线程1);t.start();// 调用sleep方法try {t.sleep(1000 * 5);} catch (InterruptedException e) {e.printStackTrace();}// 5秒之后这里才会执行。System.out.println(hello World!);}
}class MyThread extends Thread {public void run() {for (int i 0; i 10000; i) {System.out.println(Thread.currentThread().getName() --- i);}}
}输出结果部分 分析
main方法中造了一个MyThread的对象并且起了一个名字调用了start方法。
紧接着有一个sleep方法这个sleep方法是让主线程睡了还是让分线程睡了
其实是主线程。
虽然t是一个线程但是这里不能算是一个线程去调用sleep。只能理解为是一个对象去调用sleep。
t.sleep()代码的执行是在主线程里面调用的。
静态方法用类和对象调用都没有区别都只会影响主线程。
3练习题3
题目描述
银行有一个账户。
有两个储户分别向同一个账户存3000元每次存1000存3次。每次存完打印账户余额。
问题该程序是否有安全问题如果有如何解决
【提示】
1明确哪些代码是多线程运行代码须写入run()方法。
2明确什么是共享数据。
3明确多线程运行代码中哪些语句是操作共享数据的。
【拓展问题】可否实现两个储户交替存钱的操作
分析
“同一个账户”就是共享数据。
如果有多线程那就一定会有线程安全问题吗
不一定。比如一个线程操作一个账户的钱另一个线程操作另一个账户的钱这就不会有线程安全问题。
但若是多个线程操作一个共享数据就会有线程安全问题了。 本题目我们用继承Thread的方式来写。
比如现在有一个客户我们让它继承于Thread类。如下
public class AccountTest {}class Customer extends Thread{}既然大家需要共用一个账户那么这个账户如何体现共享
用静态吗
其实不用静态也可以
比如现在声明一个Account类就是账户类里面有余额如下
class Account{ //账户private double balance; //余额
}然后在客户Customer类里面声明一个Account属性如下
class Account{ //账户private double balance; //余额
}class Customer extends Thread{Account account;
}这里就不将它写成静态的了那能不能实现共享呢
这就取决于它的构造器如何去使用了。
通过构造器给当前属性实例化一下如下
class Account{ //账户private double balance; //余额
}class Customer extends Thread{Account account;//构造器public Customer(Account acct){this.accountacct;}}怎么保证造两个Customer是同一个account呢
只new一个对象然后将值传进去即可。
比如在main方法中造一个账户acct然后new一个Customer的时候将acct传进去。
public class AccountTest {public static void main(String[] args) {Account acctnew Account();new Customer(acct);}
}这样就可以创建两个Customer如下
public class AccountTest {public static void main(String[] args) {Account acctnew Account();Customer customer1new Customer(acct);Customer customer2new Customer(acct);}
}现在这两个线程就共享同一个账户acct。
以后就可以使用这种思路来让线程共享资源啦如下
public class AccountTest {public static void main(String[] args) {Account acctnew Account();Customer customer1new Customer(acct);Customer customer2new Customer(acct);}
}class Account{ //账户private double balance; //余额
}class Customer extends Thread{Account account;//构造器public Customer(Account acct){this.accountacct;}}同一个对象的实例变量是共享的。 在Thread类里面有一个可以起名字的构造器这边就使用它来给线程起个名字吧。
来个重载构造器
class Customer extends Thread{Account account;//构造器public Customer(Account acct,String name){super(name);this.accountacct;}}现在就可以用这个构造器了比如
public class AccountTest {public static void main(String[] args) {Account acctnew Account();Customer customer1new Customer(acct,小旺);Customer customer2new Customer(acct,小岁);}
}这样的话就通过构造器的方式将线程的名字赋值好了。 现在两个储户需要存钱需要在run方法里面做这个事情。
存三次就循环三次
class Customer extends Thread{//...Overridepublic void run() {for (int i 0; i 3; i) {}}
}然后就是操作账户的余额让余额balance三次增加。加钱的事情可以定义在Account类里面。如下
class Account{ //账户private double balance; //余额public void deposit(double amt){if(amt0){balanceamt;}System.out.println(Thread.currentThread().getName()存钱1000元余额为balance);}
}然后在刚才的for循环里面可以调用一下deposit方法。
class Customer extends Thread{//...Overridepublic void run() {for (int i 0; i 3; i) {account.deposit(1000);}}
}当我们调用run方法的时候就会进入for循环然后调用account的deposit方法首先往里面存了1000块钱。
然后各自线程去调用start方法他们会各自调用run方法去存钱。如下
public class AccountTest {public static void main(String[] args) {Account acctnew Account();Customer customer1new Customer(acct,小旺);Customer customer2new Customer(acct,小岁);customer1.start();customer2.start();}
}代码
package yuyi03;/*** ClassName: AccountTest* Package: yuyi03* Description:** Author 雨翼轻尘* Create 2024/1/30 0030 14:56*/
public class AccountTest {public static void main(String[] args) {Account acctnew Account();Customer customer1new Customer(acct,小旺);Customer customer2new Customer(acct,小岁);customer1.start();customer2.start();}
}class Account{ //账户private double balance; //余额public void deposit(double amt){if(amt0){balanceamt;}System.out.println(Thread.currentThread().getName()存钱1000元余额为balance);}
}class Customer extends Thread{Account account;//构造器public Customer(Account acct){this.accountacct;}public Customer(Account acct,String name){super(name);this.accountacct;}Overridepublic void run() {for (int i 0; i 3; i) {account.deposit(1000);}}
}输出结果 现在看着没有线程安全问题接下来演示一下线程安全问题。
共享数据就是“钱数”balance。
在这里加一个sleep 现在的代码
public class AccountTest {public static void main(String[] args) {Account acctnew Account();Customer customer1new Customer(acct,小旺);Customer customer2new Customer(acct,小岁);customer1.start();customer2.start();}
}class Account{ //账户private double balance; //余额public void deposit(double amt){if(amt0){balanceamt;}try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()存钱1000元余额为balance);}
}class Customer extends Thread{Account account;//构造器public Customer(Account acct){this.accountacct;}public Customer(Account acct,String name){super(name);this.accountacct;}Overridepublic void run() {for (int i 0; i 3; i) {account.deposit(1000);}}
}输出结果 可以看到出现了问题。
这就是线程安全问题怎么解决呢
balance是共享数据直接将操作写在deposit方法里面了那么可以给这个方法直接加上synchronized吗 能不能使用取决于这个this是不是唯一的。
大家不要记“继承的方式this不唯一”需要具体问题具体分析。
这个方法的调用者是Account类的对象而Account类的对象只创建了一个如下 所以现在就是acct。既然是唯一的那么线程就是安全的。
代码
package yuyi03;/*** ClassName: AccountTest* Package: yuyi03* Description:** Author 雨翼轻尘* Create 2024/1/30 0030 14:56*/
public class AccountTest {public static void main(String[] args) {Account acctnew Account();Customer customer1new Customer(acct,小旺);Customer customer2new Customer(acct,小岁);customer1.start();customer2.start();}
}class Account{ //账户private double balance; //余额public synchronized void deposit(double amt){ //this:是唯一的即为acttif(amt0){balanceamt;}try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()存钱1000元余额为balance);}
}class Customer extends Thread{Account account;//构造器public Customer(Account acct){this.accountacct;}public Customer(Account acct,String name){super(name);this.accountacct;}Overridepublic void run() {for (int i 0; i 3; i) {account.deposit(1000);}}
}输出结果 这就是之前说的同步方法可以使用在“继承Thread类的子类”中的场景了只要对象是同一个那就可以直接使用非静态同步方法了。 现在的结果显示小旺存完之后小岁才存钱要想体现交互可以让他睡一下如下 代码
package yuyi03;/*** ClassName: AccountTest* Package: yuyi03* Description:** Author 雨翼轻尘* Create 2024/1/30 0030 14:56*/
public class AccountTest {public static void main(String[] args) {Account acctnew Account();Customer customer1new Customer(acct,小旺);Customer customer2new Customer(acct,小岁);customer1.start();customer2.start();}
}class Account{ //账户private double balance; //余额public synchronized void deposit(double amt){ //this:是唯一的即为acttif(amt0){balanceamt;}try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()存钱1000元余额为balance);}
}class Customer extends Thread{Account account;//构造器public Customer(Account acct){this.accountacct;}public Customer(Account acct,String name){super(name);this.accountacct;}Overridepublic void run() {for (int i 0; i 3; i) {try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}account.deposit(1000);}}
}输出结果