并行:指兩個和多個時間在同一時刻發(fā)生。
并發(fā):指兩個或多個時間在同一時間段內發(fā)生。
在操作系統(tǒng)中,在很多道程序環(huán)境下,并發(fā)性指在同一時間段內有多個程序在同時運行,但在單CPU操作系統(tǒng)下,每一時刻只能有一道程序執(zhí)行(時間片:CPU分配給各個程序的時間),故這些程序只能是分時的交替進行(但是速度很快,把1秒鐘分成1萬個時間片)而不是我們以為的同時在運行多個程序。
倘若計算機系統(tǒng)有多個CPU,則這些可以并發(fā)執(zhí)行的程序被分配到多個處理器上,實現(xiàn)多任務并行操作,因為是微觀的,所以大家在使用電腦時感覺是多個程序同時執(zhí)行的。
從宏觀角度理解線程是并行運行的,微觀角度看的話是串行運行的,
當系統(tǒng)只有一個CPU時,線程會以某種順序執(zhí)行多個線程,我們把這種情況稱之為線程的調度。
線程和進程的區(qū)別:
進程:有獨立的內存空間,進程中的數(shù)據(jù)存放空間(堆空間和??臻g),是獨立的,至少有一個線程
線程:棧空間是獨立的,堆空間是共享的,線程消耗的資源比進程小。
線程先后執(zhí)行的順序是由CPU(JVM)調度的,進程的執(zhí)行是由CPU控制的。
在一個java程序中,至少包含兩個線程,main線程,垃圾回收線程(后臺線程,用來不定時的回收垃圾,不能說等主方法運行完了再回收,是隨機不定時動態(tài)回收的)
創(chuàng)建線程
a.繼承Thread類
b.實現(xiàn)Runnable接口(當用這種方法時,只是實現(xiàn)了這個接口,它并不是線程類,沒有start方法,所以要創(chuàng)建線程的對象)
線程類:Thread和其子類才叫做線程類
啟動線程時不要調用run方法,而是調用start方法。如果調用run方法只是單純的用對象調用了一次方法,而并沒有啟動線程,程序還只是一個線程。
繼承方式和實現(xiàn)方式的區(qū)別:
繼承方式:從多線程共享資源上分析,繼承方式不能做到3個同學吃150個蘋果
實現(xiàn)方式:共享同一個資源,3個同學吃了50個蘋果
線程不安全
解決
1.同步代碼塊
synchronized(this:當前對象的鎖){需要通同步的代碼塊}
2.同步方法
3.鎖機制
Lock是接口,創(chuàng)建其實現(xiàn)類的對象: final Lock lock=new ReentranLock()
兩個方法:
lock.lock
lock.unlock
synchronized的好與壞
安全但是性能低
建議:較少它所包含的代碼塊
面試題
StringBuffer與StringBuilder區(qū)別:
StringBuffer用synchronized修飾,安全,性能不高
StringBuilder不用synchronized修飾,不安全,性能高
ArrayList和vector(前身,安全,性能差)
Hashmap和Hashtable(前身,安全,性能差)
wait()和notify()
等待與喚醒:可以讓多個線程有序的逐條工作
wait使其下面的代碼阻塞并且釋放鎖
wait和notify必須在同步synchronized中使用
經(jīng)典的消費者案例
//共享資源案例
public class shareSource {
private String name;
private String sex;
boolean isNull=true;
//添加數(shù)據(jù)
public synchronized void add(String name,String sex) throws InterruptedException {
if(!isNull)
{
wait();
}
this.name=name;
Thread.sleep(10);
this.sex=sex;
isNull=false;
notify();
}
//輸出數(shù)據(jù)
public synchronized void print() throws InterruptedException {
if(isNull)
{
wait();
}
System.out.println(name+"---"+sex);
isNull=true;
notify();
}
}
//消費者
public class consumer implements Runnable{
shareSource s=null;
public consumer(shareSource s) {
this.s = s;
}
@Override
public void run() {
for(int i=0;i<500;i++)
{
try {
s.print();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//生產(chǎn)者
public class producer implements Runnable{
shareSource s=null;
public producer(shareSource s) {
this.s = s;
}
@Override
public void run() {
for(int i=0;i<50;i++)
{
if(i%2==0)
{
try {
s.add("李兵","男");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
else{
try {
s.add("趙瑩","女");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
//測試類
public class testThread {
public static void main(String[] args) {
shareSource s=new shareSource();
producer pp=new producer(s);
Thread p=new Thread(pp);
consumer cc=new consumer(s);
Thread c=new Thread(cc);
p.start();
c.start();
}
}