JAVA自學(xué)筆記24
1、能使用同步代碼塊就使用同步代碼塊,除非鎖對(duì)象是this,就可以考慮使用同步方法。靜態(tài)方法的鎖是類的字節(jié)碼對(duì)象。
2、JDK5新特性
1)接口Lock
void Lock()//獲取鎖
void unlock()//釋放鎖
ReentrantLock:實(shí)現(xiàn)類
public class SellTicketDemo{
public stsatic
void main(String args[]){
Thread t1=
new Thread(st,
"窗口1");
Thread t2=
new Thread(st,
"窗口2");
Thread t3=
new Thread(st,
"窗口3");t1.start();
t2.start();
t3.start();
}
}publlic class SellTicket implements Runnable{
private int tickets=
100;
private Lock
lock=
new ReentrantLock();
public void run(){
try{
lock.
lock();
if(tickets>
0){
try{
Thread.sleep(
100);
}
catch(InterruptedException e){
e.printStackTrace();
}
System.
out.println(Thread.currentThread().getName()+
"正在賣(mài)"+(tickets--)+
"張票")
})
finally{
lock.unlock();}
}
}
2)死鎖問(wèn)題
①同步弊端:效率低,容易產(chǎn)生死鎖問(wèn)題。如果出現(xiàn)了同步嵌套,就容易出現(xiàn)死鎖問(wèn)題
②是指兩個(gè)或者兩個(gè)以上的線程在執(zhí)行過(guò)程中,因爭(zhēng)奪資源產(chǎn)生的一種相互等待的現(xiàn)象。
public class MyLock{
public static final Object ObjA=
new Object();
public static final Object ObjB=
new Object();
}
public class DieLock extends Thread{
private boolean flag;
public DieLock(
boolean flag){
this.flag=flag;
public void run(){
if(flag){
Synchronized(MyLock.objA){
System.out.println(
"if objA");
Synchronized(MyLock.objB){
System.out.println(
"if objB");
}
}
}
else{
synchronized(MyLock.objB){
System.out.println(
"else objB");
Synchronized(MyLock.objA){
System.out.println(
"else objA");
}
}
}
}
}
public class DieDemo{
public static void main(String[] args){
DieLock dl1=
new DieLock(
true);
DieLock dl2=
new DieLock(
false);dl1.start();
dl2.start();
}
}
3)線程間的通信
不同種類的線程間針對(duì)同一個(gè)資源的操作,設(shè)置線程(生產(chǎn)者),獲取線程(消費(fèi)者)
public class Student{
String name;
int age;
}
public class SetThread implements Runnable{
private Student s;
private int x=
0;
public SetThread(Student s){
this.s=s;
}
public void run(){
synchronized(s){
while(
true){
if(x%
2==
0){
s.name=
"cc";
s.age=
18;
}
else{
s.name=
"dd";
s.age=
13;
}
x++;
}
}
}}
public class GetThread implements Runnable{
implements Runnable{
private Student s;
public SetThread(Student s){
this.s=s;
}
public void run(){
synchronized(s){
while(
true){System,out,println(s.name);
}}}
}
public class StudentDemo{
Student s=
new Student{};
pubic
static void main {String args[]){
SetThread st=
new SetThread(s);
GetThread gt=
new GetThread(s);
Thread t1=
new Thread(st);
Thread t1=
new Thread(gt);
t1.start();
t2.start();
}
4)等待喚醒機(jī)制
圖解:
void wait();
在其他線程調(diào)用此對(duì)象的notify()或notifyAll()方法前,導(dǎo)致該線程等待
void notify()
喚醒在此對(duì)象監(jiān)視器等待的單個(gè)線程
void notifyAll()
喚醒在此對(duì)象監(jiān)視器等待的所有線程
public class Student{
String name;
int age;
boolean flag;
}
public class SetThread implements Runnable{
private Student s;
private int x=
0;
public SetThread(Student s){
this.s=s;
}
public void run(){
while(
true){
synchronized(s){
if(s.flag){
s.wait();}
if(x%
2==
0){
s.name=
"cc";
s.age=
18;
}
else{
s.name=
"dd";
s.age=
13;
}
x++;
s.flag=
true;
s.notify();
}
}
}}
public class GetThread implements Runnable{
implements Runnable{
private Student s;
public SetThread(Student s){
this.s=s;
}
public void run(){
synchronized(s){
if(!s.flag){
s.wait();
}
while(
true){
System,out,println(s.name);
s.flag=
false;
s.notify();
}}}
}
public class StudentDemo{
Student s=
new Student{};
pubic
static void main {String args[]){
SetThread st=
new SetThread(s);
GetThread gt=
new GetThread(s);
Thread t1=
new Thread(st);
Thread t1=
new Thread(gt);
t1.start();
t2.start();
}
線程的狀態(tài)轉(zhuǎn)換圖:
3、線程組
1)java使用ThreadGroup來(lái)表示線程組,它可以對(duì)一批線程進(jìn)行分類管理,java允許程序直接對(duì)線程組進(jìn)行控制
默認(rèn)情況下,所有的線程都屬于主線程組
public final ThreadGroup getThreadGroup()
也可以給線程設(shè)置分組
Thread(ThreadGroup group,Runnable target,String name)
public class MyRunnable implements Runnable{
public void run(){
for(
int x=
0;x<
0;x++){
System.out.println(Thread.currentThread().getName()+
":"+x);
}
}
public class void ThreadGroupDemo{
public static void main(String args[]){
MyRunnable my=
new MyRunnable();
Thread t1=
new Thread(my,
"cc");
Thread t2=
new Thread(my,
"dd");ThreadGruop tg1=t1.getThreadGruop();
ThreadGruop tg2=t2.getThreadGruop();
String name1=tg1.getName();
String name2=tg2.getName();
method1();
}
}
private static void method1(){
ThreadGroup tg=
new ThreadGroup(
"這是新的組");MyRunnable my=
new MyRunnable();
Thread t1=
new Thread(tg,my,
"cc");
Thread t1=
new Thread(tg,my,
"dd");
}
//生產(chǎn)者消費(fèi)者案例優(yōu)化
public class Student{
private private String name;
int age;
private boolean flag;
public synchronized void set(String name,
int age){
if(
this.flag){
this.wait();
}
}
this.name=name;
this.age;
this.flag=
true;
this.notify();
}
public synchronized void get(){
if(!
this.flag){
this.wait();
}
}
System.out,println(
this.name);
this.flag=
false;
this.notify();
}
public class SetThread implements Runnable{
private Student s;
private int x=
0;
public SetThread(Student s){
this.s=s;
}
public void run(){
while(
true){
if(x%
2==
0){
s.set(
"cc",
23);
}
else{
s.set(
"dd",
23);
}
x++;
}
}
}}
public class GetThread implements Runnable{
implements Runnable{
private Student s;
public SetThread(Student s){
this.s=s;
}
public void run(){
synchronized(s){
if(!s.flag){
s.wait();
}
while(
true){
s.get();
}}}
}
public class StudentDemo{
Student s=
new Student{};
pubic
static void main {String args[]){
SetThread st=
new SetThread(s);
GetThread gt=
new GetThread(s);
Thread t1=
new Thread(st);
Thread t1=
new Thread(gt);
t1.start();
t2.start();
}
4、線程池
1)程序啟動(dòng)一個(gè)新線程的成本是比較高的,因?yàn)樗婕暗揭c操作系統(tǒng)進(jìn)行交互。而使用線程池可以很好地提高性能,尤其是當(dāng)程序中要?jiǎng)?chuàng)建大量生存期很短的線程時(shí),更應(yīng)該考慮使用線程池。線程池里的每一個(gè)線程代碼結(jié)束后,并不會(huì)死亡,而是再次回到線程池中成為空閑狀態(tài),等待下一個(gè)對(duì)象來(lái)使用。
在JDK5之前,必須手動(dòng)實(shí)現(xiàn)自己的線程池,從JDK5開(kāi)始,Java支持內(nèi)置線程池。
JDK5新增了一個(gè)Exexutors工廠類來(lái)產(chǎn)生線程池,有如下幾個(gè)方法:
public static ExecutorsService newCacheThreadPool()
開(kāi)啟具有緩存功能的線程池
public static ExecutorsService newFixedThreadPool(int nThreads)
創(chuàng)建指定個(gè)線程的線程池
public static ExecutorsService newSingleThreadExecutor()
創(chuàng)建1個(gè)線程池
這些方法的返回值是ExecutorsService對(duì)象。該對(duì)象表示一個(gè)線程池,可以執(zhí)行Runnable對(duì)象或者Callable對(duì)象代表的線程。
public class ExecutorsDemo{
public static void main(String args[]){
ExecutorService pool=Executors.newFixedThreadPool(
2);
pool.submit(
new MyRunnable());
pool.submit(
new MyRunnable());
pool.shutdown();
}
}
public class MyRunnable implements Runnable{
public void run(){
for(
int x=
0;x<
100;x++){
System.out.println(Thread.currenThread().getName()+
":"+x);
}
}
}}
}
可以有返回值,可以做出異常,但代碼過(guò)于復(fù)雜一般不用
接口Callable
public class CallableDemo{
ExecutorService pool=Executors.newFixedThreadPool(
2);pool.submit(
new MyCallable());
pool.submit(
new MyCallable());
}
public class MyCallable implements Callable{
for(
int x=
0;x<
100;x++){
System.out.println(Thread.currenThread().getName()+
":"+x);}
public Object
call()
throws Exception{
return null;
}
}
5、匿名內(nèi)部類實(shí)現(xiàn)多線程
new Thread(){代碼…}.start();
New Thread (new Runnable(){代碼…}}.start();
public class ThreadDemo{
public static void main(String args[]){
new Thread(){
public void run(){
for(
int x=
0;x<
100;x++){
System.
out.println(Thread.currenThread().getName()+
":"+x);
}
}
}.start();
new Thread(
new Runnable(){
public void run(){
for(
int x=
0;x<
100;x++){
System.
out.println(Thread.currenThread().getName()+
":"+x);
}
}
}).start();
}
new Thread(
new Runnable(){
public void run(){
for(
int x=
0;x<
100;x++){
System.
out.println(
"Hello"+
":"+x);
}
}
}){
public void run(){
for(
int x=
0;x<
100;x++){
System.
out.println(
"World"+
":"+x);
}
}
}.start();
}
}
6、定時(shí)器
1)定時(shí)器是一個(gè)應(yīng)用十分廣泛的線程工具,可用于調(diào)度多個(gè)定時(shí)任務(wù)以后線程的方式執(zhí)行,在java中,可以通過(guò)Timer和TimerTask類來(lái)實(shí)現(xiàn)定義調(diào)度的功能
2)Timer
public Timer()
//創(chuàng)建一個(gè)新的計(jì)時(shí)器
public void schedule(TimerTask task,long delay)
安排在指定延遲后執(zhí)行指定的任務(wù)
public void schedule(TimerTask task,long period)
安排指定的任務(wù)從指定的延遲后開(kāi)始進(jìn)行重復(fù)的固定延遲執(zhí)行
3)TimerTask
public abstract void run()
此計(jì)時(shí)器任務(wù)要執(zhí)行的操作
public boolean cancel()
//終止此計(jì)時(shí)器,丟棄所有當(dāng)前已安排的任務(wù)
public class TimerDemo{
public static void main(String args[]){
Timer t=
new Timer();
t.schedule(
new MyTask(t),
3000);
}
}
class MyTask extends TimerTask{
private Timer t;
public MyTask(){}
public MyTask(Timer t){
this.t=t;
}
public void run(){
System.out.println(
"爆炸");
t.cancel();
}
}
class DeleteFolder extends TimerTask{
public void run(){
File file=
new File(
"demo");
deleteFolder(srcFolder);
}
public void deleteFolder(File srcFolder){
File[] fileArray=srcFolder.listFiles();
if(fileArray!=
null){
for(File file:fileArray){
if(file.isDirectory()){
deleteFolder(file);
}
else{
file.delete();
}
}
srcFolder.delete();
}
}
}
public class TimerTest{
public static void main(String args[]){
Timer t=
new Timer();
String s=
"2018-8-23 15:52:24";
SimpleDateFormat sdf =
new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss");
Date d=sdf.parse(s);t.schdule(
new DeleteFolder(),d);
}
}
7、多線程常見(jiàn)面試題回顧
1)多線程有幾種實(shí)現(xiàn)方案,分別是哪幾種。
兩(三)種。繼承Thread類,實(shí)現(xiàn)Runnable接口,(實(shí)現(xiàn)Callable接口)
2)同步有幾種方式,分別是什么?
同步代碼塊
同步方法
3)
8、面向?qū)ο笏枷朐O(shè)計(jì)原則及常見(jiàn)設(shè)計(jì)模式
1)面向?qū)ο笏枷朐O(shè)計(jì)原則
2)設(shè)計(jì)模式
設(shè)計(jì)模式是一套被反復(fù)使用,多數(shù)人知曉的,經(jīng)過(guò)分類編目的代碼設(shè)計(jì)經(jīng)驗(yàn)總結(jié)。使用設(shè)計(jì)模式是為了可重用代碼,讓代碼更容易被他人理解,保證代碼的可靠性。
轉(zhuǎn)載于:https://www.cnblogs.com/Tanqurey/p/10485333.html
總結(jié)
以上是生活随笔為你收集整理的JAVA自学笔记24的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。