一脓豪、 java基礎(chǔ)
1. java多線程基礎(chǔ)
1) 多線程的創(chuàng)建方式
1.多線程創(chuàng)建方式1
packagecom.qyl.springboot.controller;
/**
* 多線程的創(chuàng)建
* ? ? 方式一: 繼承與Thread類
* ? ? 1.創(chuàng)建一個(gè)子類類繼承Thread
* ? ? 2.在子類中重寫Thread的run()方法(線程要做的事寫到run()方法中)
* ? ? 3.創(chuàng)建該子類的對(duì)象 (在主線程里面創(chuàng)建)
* ? ? 4.通過此對(duì)象調(diào)用start方法
* ? ? 例子 : 遍歷100以內(nèi)的所有的偶數(shù)
*/
// 1.創(chuàng)建一個(gè)子類類繼承Thread
classMyThreadextendsThread{
//2.在子類中重寫Thread的run()方法 ? 線程要做的事寫到run()方法中
@Override
publicvoidrun() {
for(inti=0;i<100;i++) {
if(i%2==0){
System.out.println(i+"---"+Thread.currentThread().getName());
? ? ? ? ?? }
? ? ?? }
?? }
};
publicclassThreadTest{
publicstaticvoidmain(String[]args) {
// 3.創(chuàng)建該子類的對(duì)象
//主線程執(zhí)行
MyThreadmyThread=newMyThread();
MyThreadmyThread1=newMyThread();
//4.通過此對(duì)象調(diào)用start方法
//創(chuàng)建出來的線程執(zhí)行
/**
* 用start()方法啟動(dòng)? run()啟動(dòng)不了多線程效果
*/
myThread.start();
myThread1.start();//鄉(xiāng)啟動(dòng)多個(gè)就多創(chuàng)建對(duì)象即可
for(inti=0;i<100;i++) {
if(i%2==0){
System.out.println(i+" ++++++++++++++-"+Thread.currentThread().getName());
? ? ? ? ?? }
? ? ?? }
? ? ? ? //這種方法也可以 ? 匿名子類
System.out.println("http://///////////////");
newThread(){
@Override
publicvoidrun() {
for(inti=0;i<100;i++) {
if(i%2!=0){
System.out.println(Thread.currentThread().getName()+"http:////////////////"+i);
? ? ? ? ? ? ? ? ?? }
? ? ? ? ? ? ?? }
? ? ? ? ?? }
}.start();
?? }
}
輸出結(jié)果:
48---Thread-0
78---Thread-1
50---Thread-0
18 ++++++++++++++-main
52---Thread-0
80---Thread-1
82---Thread-1
84---Thread-1
2. 多線程創(chuàng)建方式2
實(shí)現(xiàn)Runnable接口
1.創(chuàng)建一個(gè)實(shí)現(xiàn)了Run那邊了接口的類
2.實(shí)現(xiàn)類去實(shí)現(xiàn)Runable中的抽象方法
3.創(chuàng)建實(shí)現(xiàn)類的對(duì)象
4.將此對(duì)象作為參數(shù)傳遞到Thread類的構(gòu)造器中饶唤,創(chuàng)建Thread類的對(duì)象
5.通過Thread類的對(duì)象調(diào)用start()方法
packagecom.qyl.springboot.controller;
/**
* ###? 2)? 多線程創(chuàng)建方式2
*
* 實(shí)現(xiàn)Runnable接口
*
* 1.創(chuàng)建一個(gè)實(shí)現(xiàn)了Run那邊了接口的類
* 2.實(shí)現(xiàn)類去實(shí)現(xiàn)Runable中的抽象方法
* 3.創(chuàng)建實(shí)現(xiàn)類的對(duì)象
* 4.將此對(duì)象作為參數(shù)傳遞到Thread類的構(gòu)造器中,創(chuàng)建Thread類的對(duì)象
* 5.通過Thread類的對(duì)象調(diào)用start()方法
*/
//1.創(chuàng)建一個(gè)實(shí)現(xiàn)了Run那邊了接口的類
classMyRunnableimplementsRunnable{
//2.實(shí)現(xiàn)類去實(shí)現(xiàn)Runable中的抽象方法
@Override
publicvoidrun() {
for(inti=0;i<100;i++) {
if(i%2==0){
System.out.println(""+i+" ++++++++++++++-"+Thread.currentThread().getName());
? ? ? ? ?? }
? ? ?? }
?? }
}
publicclassRunableTest{
publicstaticvoidmain(String[]args) {
//3.創(chuàng)建實(shí)現(xiàn)類的對(duì)象
MyRunnablem1=newMyRunnable();
//4.將此對(duì)象作為參數(shù)傳遞到Thread類的構(gòu)造器中双抽,創(chuàng)建Thread類的對(duì)象
Threadthread=newThread(m1);
thread.setName("liudeh");
thread.start();
Threadt2=newThread(m1);
t2.setName("liudsssssssssseh");
t2.start();
?? }
}
2.線程生命周期
創(chuàng)建 調(diào)用start()
就緒 sleep()時(shí)間到,join()結(jié)束,獲取同步鎖,notify()/notifyALL(),resume()
阻塞 失去cpu執(zhí)行權(quán),或者yield()
運(yùn)行 sleep(),join(),等待同步鎖,wait(),suspend()
死亡 執(zhí)行完run(),調(diào)用stop(),出現(xiàn)Error/Exception且沒處理
3.線程同步
1.同步代碼塊
/**
* 線程同步與安全
* 處理共享數(shù)據(jù)的時(shí)候會(huì)出現(xiàn)線程安全問題
* 加鎖解決
* 4.在java中,通過同步機(jī)制來解決線程安全問題
* 方式一: 同步代碼塊
*? synchronized (同步監(jiān)視器){
* ? ?? //需要被同步的代碼 (吃操作共享數(shù)據(jù)的代碼就是需要被同步的代碼)
*}
*? 說明: ?1.(吃操作共享數(shù)據(jù)的代碼就是需要被同步的代碼)
* ? ? ?? 2.同步監(jiān)視器就是 鎖 任何類的對(duì)象都能充當(dāng)鎖
* ? ? ? ?? 鎖的要求: 多個(gè)線程供用同一把鎖
* ? ? ? ?? 哪怕你用一個(gè)狗 dag對(duì)象都可以
* 方式二: 同步方法
*
*
* 5.同步的方式雖然解決了線程安全
*? 缺點(diǎn)是同步代碼塊里面是單線程
*/
packagecom.qyl.java;
/**
* 開發(fā)一個(gè)類 實(shí)現(xiàn)Runnable 并重寫 run() 方法
*/
classWindowimplementsRunnable{
privateinttitck=100;
Objectobject=newObject();
@Override
publicvoidrun() {
while(true){
//同步代碼塊
synchronized(object){
if(titck>0){
System.out.println(Thread.currentThread().getName()+" 賣票-----票號(hào)碼為: "+titck);
titck--;
}else{
break;
? ? ? ? ? ?? }
? ? ? ?? }
? ?? }
?? }
}
/**
* 線程同步與安全
* 處理共享數(shù)據(jù)的時(shí)候會(huì)出現(xiàn)線程安全問題
* 加鎖解決
* 4.在java中,通過同步機(jī)制來解決線程安全問題
* 方式一 : 同步代碼塊
*? synchronized (同步監(jiān)視器) {
* ? ?? //需要被同步的代碼 (吃操作共享數(shù)據(jù)的代碼就是需要被同步的代碼)
*? }
*? 說明:? 1.(吃操作共享數(shù)據(jù)的代碼就是需要被同步的代碼)
* ? ? ?? 2.同步監(jiān)視器就是 鎖 任何類的對(duì)象都能充當(dāng)鎖
* ? ? ? ?? 鎖的要求 : 多個(gè)線程供用同一把鎖
* ? ? ? ?? 哪怕你用一個(gè)狗 dag對(duì)象都可以
* 方式二 : 同步方法
*
*
* 5.同步的方式雖然解決了線程安全
*? 缺點(diǎn)是同步代碼塊里面是單線程
*/
publicclassSyncThread{
publicstaticvoidmain(String[]args) {
Windowm1=newWindow();
Threadt1=newThread(m1);
Threadt2=newThread(m1);
Threadt3=newThread(m1);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
?? }
}
注意:implement Runnable 的時(shí)候 this(當(dāng)前對(duì)象 ) 就可以當(dāng)做鎖? extends Threads的時(shí)候 不行
2.同步方法
// 1.一種情況可以直接把run改為同步的,但是要注意場(chǎng)景
classWindowimplementsRunnable{
privateinttitck=100;
Objectobject=newObject();
@Override
publicsynchronizedvoidrun() {
while(true){
//同步代碼塊
synchronized(this){
if(titck>0){
System.out.println(Thread.currentThread().getName()+" 賣票-----票號(hào)碼為: "+titck);
titck--;
}else{
break;
? ? ? ? ? ?? }
? ? ? ?? }
? ?? }
?? }
}
1.同步方法解決Runnable
packagecom.qyl.java;
/**
* 開發(fā)一個(gè)類 實(shí)現(xiàn)Runnable 并重寫 run() 方法
*/
classWindowimplementsRunnable{
privateinttitck=100;
Objectobject=newObject();
@Override
publicvoidrun() {
while(true){
sync();
? ?? }
?? }
privatesynchronizedvoidsync(){//同步監(jiān)視器就是this
//同步代碼塊
if(titck>0){
try{
Thread.sleep(10);
}catch(InterruptedExceptione) {
e.printStackTrace();
? ? ? ? ? ? ?? }
System.out.println(Thread.currentThread().getName()+" 賣票-----票號(hào)碼為: "+titck);
titck--;
? ? ? ? ?? }
?? }
}
/**
* 線程同步與安全
* 處理共享數(shù)據(jù)的時(shí)候會(huì)出現(xiàn)線程安全問題
* 加鎖解決
* 4.在java中,通過同步機(jī)制來解決線程安全問題
* 方式一 : 同步代碼塊
*? synchronized (同步監(jiān)視器) {
* ? ?? //需要被同步的代碼 (吃操作共享數(shù)據(jù)的代碼就是需要被同步的代碼)
*? }
*? 說明:? 1.(吃操作共享數(shù)據(jù)的代碼就是需要被同步的代碼)
* ? ? ?? 2.同步監(jiān)視器就是 鎖 任何類的對(duì)象都能充當(dāng)鎖
* ? ? ? ?? 鎖的要求 : 多個(gè)線程供用同一把鎖
* ? ? ? ?? 哪怕你用一個(gè)狗 dag對(duì)象都可以
* 方式二 : 同步方法
* ? ? 如果操作共享數(shù)據(jù)的代碼完整的在一個(gè)方法中,我們可以將該方法做成同步的
* ? ? 1.一種情況可以直接把run改為同步的,但是要注意場(chǎng)景
*
* 5.同步的方式雖然解決了線程安全
*? 缺點(diǎn)是同步代碼塊里面是單線程
*/
publicclassSyncThread{
publicstaticvoidmain(String[]args) {
Windowm1=newWindow();
Threadt1=newThread(m1);
Threadt2=newThread(m1);
Threadt3=newThread(m1);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
?? }
}
2.同步方法解決thread
packagecom.qyl.java;
classWindowsextendsThread{
privatestaticinttickets=100;
privatestaticObjectobject=newObject();
@Override
publicvoidrun() {
while(true) {
//同步代碼塊
show();
? ? ?? }
?? }
privatestaticsynchronizedvoidshow(){//加個(gè)static 就可以了
if(tickets>0) {
try{
sleep(10);
}catch(InterruptedExceptione) {
e.printStackTrace();
? ? ?? }
System.out.println(Thread.currentThread().getName()+" 賣票-----票號(hào)碼為: "+tickets);
tickets--;
?? }
}
}
publicclassextendsThread{
publicstaticvoidmain(String[]args) {
Windowsw1=newWindows();
Windowsw2=newWindows();
Windowsw3=newWindows();
w1.setName("窗口1");
w2.setName("窗口2");
w3.setName("窗口3");
w1.start();
w2.start();
w3.start();
?? }
}
4.Thread 的常用方法介紹:
1) start():
啟動(dòng)當(dāng)前線程莺掠,調(diào)用當(dāng)前線程的run()方法 。
2) run():
通常是重寫Thread 的run()方法 將線程要做的事情聲明在該方法中
3) currentThread() :
Thread 的靜態(tài)方法 獲取到當(dāng)前線程
4)getName() setName():
給線程名字的方法
package com.qyl.springboot.controller;
class MyThread1 extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if(i % 2 == 0 ){
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//Thread.currentThread().setName("lalala"); 線程命名 方式1
System.out.println(Thread.currentThread().getName()+"*******"+i);
}
}
}
}
public class ThreadTest1 {
public static void main(String[] args) {
MyThread1 myThread1 = new MyThread1();
//線程命名 方式2
myThread1.setName("huren");
myThread1.start();
//給主線程命名
Thread.currentThread().setName("zongguanjun");
for (int i = 0; i < 100; i++) {
if(i % 2 == 0 ){
//Thread.currentThread().setName("lalala"); 線程命名
System.out.println(Thread.currentThread().getName()+"*******///////////"+i);
}
}
}
}
------------------------通過構(gòu)造器命名線程
package com.qyl.springboot.controller;
class MyThread1 extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if(i % 2 == 0 ){
//Thread.currentThread().setName("lalala"); 線程命名 方式1
System.out.println(Thread.currentThread().getName()+"*******"+i);
}
if(i % 20 == 0){
yield();
}
}
}
//線程命名方式3? 通過構(gòu)造器命名
public MyThread1(String name){
super(name);
}
}
public class ThreadTest1 {
public static void main(String[] args) {
MyThread1 myThread1 = new MyThread1("sssssss");
//線程命名 方式2
myThread1.setName("huren");
myThread1.start();
//給主線程命名
Thread.currentThread().setName("zongguanjun");
for (int i = 0; i < 100; i++) {
if(i % 2 == 0 ){
//Thread.currentThread().setName("lalala"); 線程命名
System.out.println(Thread.currentThread().getName()+"*******///////////"+i);
}
}
}
}
5)yiel ():
釋放當(dāng)前cpu的執(zhí)行權(quán)
6)join ():
在線程a中調(diào)用線程b的join()方法闯冷,此時(shí)線程a進(jìn)入阻塞狀態(tài)砂心,等b執(zhí)行完之后,a結(jié)束阻塞繼續(xù)執(zhí)行
7) stop():
強(qiáng)制結(jié)束該線程蛇耀,不推薦使用
8) sleep(lang millitime):
當(dāng)前線程睡眠指定的一段時(shí)間
9) isAlive()
判斷當(dāng)前線程是否存活
10)property()get辩诞,set
線程的優(yōu)先級(jí) 1-10 默認(rèn)5
public void? newRunnableMethod () {
new Thread(new Runnable() {
@Override
public void run() {
// 存放所有openid
List openids = new ArrayList<>();
List usersGuid = new ArrayList<>();
SqlSession sqlSession = sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH, false);
Task_Info_News_ReadMapper mapper = sqlSession.getMapper(Task_Info_News_ReadMapper.class);
try{
// 組裝info_news_read 表所需要的數(shù)據(jù),并存入數(shù)據(jù)庫(kù)中
for(int i = 0; i< list.size();i++){
String strUserGuid =? (String)list.get(i).get("strUserGuid");
// 通過臨時(shí)存放usersGuid,去重(對(duì)根據(jù)范圍查出數(shù)據(jù)進(jìn)行去重)
if(!usersGuid.contains(strUserGuid)){
usersGuid.add(strUserGuid);
// 獲取openid
Object strOpenid = list.get(i).get("strOpenid");
// 如果openid不為空,則放入openids集合中(用來推送模板消息)
if(strOpenid != null){
openids.add(strOpenid.toString());
}
list.get(i).put("strGuid", UUID.randomUUID().toString());
list.get(i).put("strNewsGuid",info_News.getStrGuid());
list.get(i).put("strCreator",info_News.getStrCreator());
list.get(i).put("dtCreateTime", info_News.getDtCreateTime());
mapper.insertMap(list.get(i));
}
if(i % 1000 == 0 || i == list.size() - 1){
sqlSession.commit();
sqlSession.clearCache();
}
}
}catch (Exception e) {
logger.info("事物已回滾");
loggerErr.info("發(fā)布任務(wù)失敗 ==>" + e.getMessage());
sqlSession.rollback();
e.printStackTrace();
}finally {
sqlSession.close();
}
PropertiesUtils utils = null;
try {
utils = new PropertiesUtils("global/param_hexi.properties");
} catch (Exception e) {
logger.info("global/param_hexi.properties 文件找不到");
e.printStackTrace();
return;
}
// 微信模板消息,任務(wù)的模板id
if(openids.size() > 0){
String template_id = utils.getProperty("template_id");
sendNewsToWebchatUser(template_id, openids, info_News);
}
}
}).start();
}
//不同的寫法
package com.qyl.java;
/**
* 開發(fā)一個(gè)類 實(shí)現(xiàn)Runnable 并重寫 run() 方法
*/
class MyThreadRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 == 0){
System.out.println(Thread.currentThread().getName() + "=================" +i);
}
}
}
}
/**
* 線程同步與安全
*/
public class SyncThreadTest {
public static void main(String[] args) {
MyThreadRunnable m1 = new MyThreadRunnable();
Thread t1 = new Thread(m1);
t1.setName("子線程1");
t1.start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 != 0){
Thread.currentThread().setName("主線程");
System.out.println(Thread.currentThread().getName() + "=================" +i);
}
}
}
}).start();
}
}
5.使用同步機(jī)制將單例模式中的懶漢式改寫為線程安全的
1.效率較低的方式
package com.qyl.java;
/**
* 使用同步機(jī)制將單例模式中的懶漢式改寫為線程安全的
*/
public class BankTest {
}
class Bank{
private Bank(){}
private static Bank instance = null;
public static? Bank getInstance(){ //加上synchronized就變成線程安全的了
synchronized () {
if (instance == null){
instance = new Bank();
}
return instance;
}
}
}
2.效率高點(diǎn)
package com.qyl.java;
/**
* 使用同步機(jī)制將單例模式中的懶漢式改寫為線程安全的
*/
public class BankTest {
}
class Bank{
private Bank(){
}
private static Bank instance = null;
public static? Bank getInstance(){ //加上synchronized就變成線程安全的了
if (instance == null) {
synchronized (Bank.class) {
if (instance == null) {
instance = new Bank();
}
}
}
return instance;
}
}
6.線程死鎖問題
1.死鎖案例
package com.qyl.java;
/**
* 演示死鎖問題
*/
public class SiSuo {
public static void main(String[] args) {
StringBuffer s1 = new StringBuffer();
StringBuffer s2 = new StringBuffer();
new Thread(){
@Override
public void run() {
synchronized (s1){
s1.append("a");
s2.append("1");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (s2){
s1.append("b");
s2.append("2");
System.out.println(s1);
System.out.println(s2);
}
}
}
}.start();
new Thread(new Runnable() {
@Override
public void run() {
synchronized (s2){
s1.append("c");
s2.append("3");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (s1){
s1.append("d");
s2.append("4");
System.out.println(s1);
System.out.println(s2);
}
}
}
}).start();
}
}
2.解決線程安全問題三 Lock鎖
Inspection '在使用阻塞等待獲取鎖的方式中纺涤,必須在try代碼塊之外译暂,并且在加鎖方法與try代碼塊之間沒有任何可能拋出異常的方法調(diào)用,避免加鎖成功后撩炊,在finally中無法解鎖外永。說明一:如果在lock方法與try代碼塊之間的方法調(diào)用拋出異常,那么無法解鎖拧咳,造成其它線程無法成功獲取鎖伯顶。說明二:如果lock方法在try代碼塊之內(nèi),可能由于其它方法拋出異常,導(dǎo)致在finally代碼塊中砾淌,unlock對(duì)未加鎖的對(duì)象解鎖啦撮,它會(huì)調(diào)用AQS的tryRelease方法(取決于具體實(shí)現(xiàn)類),拋出IllegalMonitorStateException異常汪厨。說明三:在Lock對(duì)象的lock方法實(shí)現(xiàn)中可能拋出unchecked異常赃春,產(chǎn)生的后果與說明二相同。' options
package com.qyl.java;
import java.util.concurrent.locks.ReentrantLock;
class WindowLock implements Runnable{
private int titck = 100;
//1.實(shí)例化一個(gè)lock
private ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true){
try {
lock.lock();
//2.調(diào)用lock()
if (titck> 0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" 賣票-----票號(hào)碼為: " + titck );
titck--;
} else {
break;
}
} finally {
//調(diào)用解鎖方法
lock.unlock();
}
}
}
}
public class LockTest {
public static void main(String[] args) {
WindowLock m1 = new WindowLock();
Thread t1 = new Thread(m1);
Thread t2 = new Thread(m1);
Thread t3 = new Thread(m1);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
7.wait() notify()
1.兩個(gè)線程交叉打印100以內(nèi)的數(shù)
package com.qyl.springboot.controller;
//? ? 2個(gè)線程交叉打印100以內(nèi)的數(shù)字
class WaitNotify implements Runnable{
private int number = 1;
@Override
public void run() {
while (true){
synchronized (this) {
//喚醒全部線程
//notifyAll();
//喚醒線程
notify();
if (number<=100){
//睡眠 不釋放線程 不釋放鎖
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"? ---打印了 : "+number);
number++;
//等待? 但是釋放線程 釋放鎖
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
break;
}
}
}
}
}
public class WaitNotifyTest {
public static void main(String[] args) {
WaitNotify w1 = new WaitNotify();
Thread t1 = new Thread(w1);
Thread t2 = new Thread(w1);
t1.setName("線程1 +++++: ");
t2.setName("線程2 -----: ");
t1.start();
t2.start();
}
}
2.wait()劫乱,notify()织中, notifyAll()
只能用在同步代碼塊或者方法中? lock不能用
并且調(diào)用者必須是同步監(jiān)視器
這三個(gè)方法是定義在對(duì)象Object中的 所以都可以用對(duì)象調(diào)
3.sleep() 和wait()區(qū)別
相同點(diǎn):都可以使得當(dāng)前線程進(jìn)入阻塞狀態(tài)
不同點(diǎn): 1) Thread類中聲明Sleep()? ,Object類中聲明Wait()
2) sleep()不會(huì)釋放鎖衷戈,wait() 會(huì)
3.)sleep ()在任何場(chǎng)景都可調(diào)用狭吼,wait只能在同步代碼中調(diào)用
8.測(cè)試題
1.存錢 ,兩個(gè)人 公用一個(gè)賬戶,各村三次 每次1000
方法一:
package com.qyl.springboot.controller;
/**
* 測(cè)試
* 存錢 ,兩個(gè)人 公用一個(gè)賬戶,各村三次 每次1000
* 1.多線程 : 兩個(gè)人
* 2.共享數(shù)據(jù) : 賬戶
* 所以有了線程安全問題
*/
public class AccountTest {
public static void main(String[] args) {
//定義初始化的賬戶
Account account = new Account(1000);
//聲明兩個(gè)對(duì)象 去開線程
Customer c1 = new Customer(account);
Customer c2 = new Customer(account);
c1.setName("甲");
c2.setName("乙");
c1.start();
c2.start();
}
}
/**
* 創(chuàng)建一個(gè)賬戶類
*/
class Account {
//聲明賬戶余額
private double balance;
//構(gòu)造器
public Account(double balance) {
this.balance = balance;
}
//往里面存錢的方法
//加synchronize 同步
public synchronized void cunQian (double atm){
if ((atm>0)){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("當(dāng)前余額: "+balance);
balance += atm;
System.out.println(Thread.currentThread().getName()+"? : 存了 "+atm+" 元,已到賬.當(dāng)前余額為"+balance+"員");
}
}
}
//用戶類,繼承Thread
class Customer extends Thread{
//注入 Account
private Account account;
//構(gòu)造器
public Customer(Account account) {
this.account = account;
}
//子類重寫父類Run方法
@Override
public void run() {
for (int i = 0; i < 3; i++) {
//調(diào)用存錢方法
account.cunQian(1000);
}
}
}
方法二:
package com.qyl.springboot.javaTest;
public class CustomerQyl extends Thread{
private AccountQyl accountQyl;
public CustomerQyl(AccountQyl accountQyl) {
this.accountQyl = accountQyl;
}
@Override
public? void run() {
for (int i = 0; i < 4; i++) {
String s =? accountQyl.Pay(1000);
System.out.println(Thread.currentThread().getName()+"? ***? "+s);
}
}
}
package com.qyl.springboot.javaTest;
public class AccountQyl {
private double balance;
public AccountQyl(double balance) {
this.balance = balance;
}
public synchronized String Pay (double atm){
if (atm>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("當(dāng)前余額: "+balance);
balance += atm;
System.out.println(Thread.currentThread().getName()+"? : 存了 "+atm+" 元,已到賬.當(dāng)前余額為"+balance+"員");
}
return "存錢成功";
}
}
package com.qyl.springboot.javaTest;
public class testSync {
public static void main(String[] args) {
AccountQyl accountQyl = new AccountQyl(300);
CustomerQyl c1 = new CustomerQyl(accountQyl);
CustomerQyl c2 = new CustomerQyl(accountQyl);
c1.setName("甲");
c2.setName("乙");
c1.start();
c2.start();
}
}
2.java? 遞歸
package com.esint.jm.wx_hxpublic.util;
//遞歸 漢諾塔
public class QylDiGuiTest {
static int times = 0;
public? static void? move (int num , char source , char dest){
System.out.println("第"+(++times)+"步驟? "+num +" 號(hào)盤子從 "+source+" 柱子到 "+dest+"柱子");
}
public static void hnt (int n,char source,char mid,char dest){
if (1 == n){
move(n,source,dest);
}else {
hnt(n-1,source,dest,mid);
move(n,source,dest);
hnt(n-1,mid,source,dest);
}
}
public static void main(String[] args) {
hnt(5,'A','B','C');
}
}