-------
android培訓、java培訓、期待與您交流! ----------
1:多線程
(1)線程:線程是進行的執行單元,執行路徑。
進程:就是正在運行的程序。一塊正在被使用的內存區域。
如果一個應用程序的執行只有一條執行路徑,被稱爲單線程程序。
如果一個應用程序的執行有多條執行路徑,被稱爲多線程程序。
舉例:
迅雷下載,360管理界面,班長請吃飯,去醫院體檢
(2)JVM的啓動是多線程的嗎?
是。因爲如果JVM啓動只啓動了main線程的話,那麼,在程序的執行過程中,
有可能會引發內存溢出,而java很少看到這種情況,爲什麼呢,就是因爲,
java的垃圾回收線程一直也在運行,當內存不夠的情況,會自動去掃描內存中
是否有垃圾存在,有就立馬清除。
這樣來說,最低有兩個線程啓動了。所以,JVM的啓動是多線程的。
(3)自己如何模擬多線程程序
A:繼承Thread類
步驟:
a:創建一個類,繼承Thread類
b:重寫run方法
c:創建類對象,調用start方法
代碼體現:
public class ThreadDemo extends Thread
{
@Override
public void run()
{
for(int x=0; x<100; x++)
{
System.out.println(getName()+"***"+x);
}
}
}
public class ThreadDemoTest
{
public static void main(String[] args)
{
ThreadDemo td1 = new ThreadDemo("劉備");
ThreadDemo td2 = new ThreadDemo("孫權");
td1.start();
td2.start();
}
}
B:實現Runnable接口
步驟:
a:創建一個類,實現Runnable接口
b:重寫run方法
c:創建Thread類對象,創建Runnable子類對象,把Runnable的子類
對象作爲構造參數傳遞給Thread的構造方法
d:調用start方法
代碼體現:
public class RunnableDemo implements Runnable
{
@Override
public void run()
{
for(int x=0; x<100; x++)
{
System.out.println(Thread.currentThread().getName()+"***"+x);
}
}
}
public class ThreadDemoTest
{
public static void main(String[] args)
{
RunnableDemo rd = new RunnableDemo();
Thread td1 = new Thread(rd,"林青霞");
Thread td2 = new Thread(rd,"劉意");
td1.start();
td2.start();
}
}
(4)實現多線程的方式有幾種,分別怎麼實現?
(5)啓動線程調用的是哪個方法,它做了什麼事情?
啓動線程調用的是start()方法。
它啓動線程,並且自動調用了run()方法。
start()和run()的區別?
(6)線程的生命週期及每個狀態的特點。
新建:創建線程對象
就緒:具有執行資格,沒有執行權
運行:具有執行資格,有執行權
阻塞:沒有執行資格,沒有執行權
死亡:對象變成垃圾
內存體現:
(7)下午通過賣票程序演示出線程安全問題。
A:線程安全是怎麼產生的?
線程的隨機性
線程的延遲性
B:如何判斷某段代碼有沒有線程安全問題呢?
a:有沒有共享數據
b:看是否有多條語句操作共享數據
c:看是否有多個線程進行操作
c:如何解決線程安全問題?
a:同步代碼塊
synchronized(對象)
{
需要被同步的代碼。
}
對象:可以是任意對象。
b:同步方法
在方法上添加synchronized關鍵字即可
鎖對象:this
注意:靜態方法的鎖對象 當前類的字節碼文件對象。
類名.class
D:同步前提
a:兩個以上的線程操作的時候
b:對這多個線程加同步必須使用的是同一把鎖
E:同步弊端
每次程序的執行都會去判斷鎖對象,消耗了資源,降低了效率。
線程安全,效率低。
線程不安全,效率高。
開發中的一個難題:要麼效率,要麼安全。
(8)賣票程序
public class Ticket implements Runnable
{
//定義100張票
private int tickets = 100;
@Override
public void run()
{
while(true)
{
synchronized(this){
if(tickets>0)
{
try{
Thread.sleep(10);
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在賣出第"+(tickets--)+"張票");
}
}
}
}
}
public class Test
{
public static void main(String[] args)
{
Ticket t = new Ticket();
Thread t1 = new Thread(t,"窗口1");
Thread t2 = new Thread(t,"窗口2");
Thread t3 = new Thread(t,"窗口3");
Thread t4 = new Thread(t,"窗口4");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
(9)單例設計模式的懶漢式,請問他有沒有線程安全問題
public class Student
{
private Student(){}
private static Student s = null;
public synchronized static Student getStudent()
{
//t1,t2,t3
if(s==null)
{
//t1,t2,t3
s = new Student();
//t1線程首先創建了一個對象
//t2線程繼續創建了一個對象
//t3線程又創建了一個對象
}
return s;
}
}
A:延遲加載
B:線程安全問題
//開發中,用餓漢式即可。
public class Student
{
private Student(){}
private static Student s = new Student();
public static Student getStudent()
{
return s;
}
}
線程範圍內的共享數據:在同一個線程數據共享,但在不同線程,數據不共享。
代碼體現:
private static int date = 0;//共享數據
public static void main(String[] args) {
for( int i=0;i<=1;i++){
new Thread(new Runnable(){
@Override
public void run() {
date = new Random().nextInt();
System.out.println("***"+Thread.currentThread().getName()+"***"+date);
new A().get();
new B().get();
}
}).start();
}
}
static class A{
public void get(){
System.out.println("A***"+Thread.currentThread().getName()+"***"+date);
}
}
static class B{
public void get(){
System.out.println("B***"+Thread.currentThread().getName()+"***"+date);
}
}
}