首頁技術(shù)文章正文

多線程的總結(jié)與常見問題解析

更新時(shí)間:2018-11-26 來源:黑馬程序員 瀏覽量:

  【創(chuàng)建多線程的第一種方式:--繼承Thread類】

  1:定義一個(gè)類繼承Thread類

  2:重寫Thread類中的run方法

  3:創(chuàng)建該類的實(shí)例,并調(diào)用start方法。

  【start方法的作用】:A、啟動(dòng)線程。B、調(diào)用run方法

  1、模擬一個(gè)多線程:

  class MyThread extends Thread{

  public void run(){

  for(int i=1;i<500;i++){

  System.out.println("MyThread:"+i);

  }

  }

  }

  public class Demo1{

  public Static void main(String[] args){

  MyThread my = new MyThread();

  my.start();

  for(int j=1;j<500;j++){

  System.out.println("main:"+i);

  }

  }

  }

  2、匿名內(nèi)部類的線程實(shí)現(xiàn)方式:

  public class Demo2{

  public static void main(String[] args){

  new Thread{

  public void run(){

  for(int=i;i<100;i++){

  System.out.println("MyThread:"=i);

  }

  }

  }.start;

  }

  for(int i=1;i<100;i++){

  System.out.println("main:"+i);

  }

  }

  3、模擬一個(gè)QQ聊天的線程:

  class Video extends Thread{

  public void run(){

  while(true){

  System.out.println("視頻中...");

  }

  }

  }

  class Talk extends Thread{

  public void run(){

  while(true){

  System.out.println("聊天中...");

  }

  }

  }

  public class Demo3{

  public static void main(String[] args){

  Video v = new Video();

  Talk t = new Video();

  v.start();

  t.start();

  for(int i=1;i<100;i++){

  System.out.println("main:"+i);

  }

  }

  }

  -------------------------------------------------------------------------------------------------------

  【創(chuàng)建線程的第二種方式:--實(shí)現(xiàn)Runnable接口】

  1、實(shí)現(xiàn)Runnable接口

  2、重寫Runnable接口中的run方法

  3、將Runnable接口中的子類對象作為實(shí)際參數(shù),傳遞給Thread類的構(gòu)造方法

  4、調(diào)用Thread類中的start方法開啟線程

  1、public class Demo1{

  public static void main(String[] args){

  MyRun my = new MyRun();

  Thread t = new Thread(my);

  t.start();

  for(int i=1;i<100;i++){

  System.out.println("main:"+i);

  }

  }

  }

  class MyRun implements Runnable{

  public void run(){

  for(int i=1;i<100;i++){

  System.out.println("MyRun:"+i);

  }

  }

  }

  2、模擬賣票系統(tǒng)【實(shí)現(xiàn)Runnable接口】

  public class Demo{

  public static void main(String[] args){

  MyRunTick mt = new MyRunTick();

  Thread t1 = new Thread(mt,"一號(hào)窗口");

  Thread t2 = new Thread(mt,"二號(hào)窗口");

  Thread t3 = new Thread(mt,"三號(hào)窗口");

  Thread t4 = new Thread(mt,"四號(hào)窗口");

  t1.start();

  t2.start();

  t3.start();

  t4.start();

  }

  }

  class MyRunTicket implements Runnable{

  private int ticket = 100;

  public void run(){

  while(true){

  synchronized(this){

  if(ticket > 0){

  System.out.println(Thread.currentThread().getName()+"賣:"+this.ticket+"號(hào)票");

  try{

  Thread.sleep(1);

  }catch(InterruptedException e){

  e.printStackTrace();

  }

  ticket--;

  }else{

  System.out.println(Thread.currentThread().getName()+"票已賣完。。");

  break;

  }

  }

  }

  }

  }

  總結(jié):同步的前提是必須有兩個(gè)或者兩個(gè)以上的線程,多個(gè)線程使用的是同一個(gè)鎖。

  線程同步的前提:1、必須是多個(gè)線程使用同一個(gè)鎖;

  2、必須保證同步中只能有一個(gè)線程在運(yùn)行

  -------------------------------------------------------------------------------------------------------

  1、實(shí)現(xiàn)方式和繼承方式有什么區(qū)別?

  實(shí)現(xiàn)的好處是:避免了單繼承的局限性。---->> 定義線程的時(shí)候最好使用實(shí)現(xiàn)方式

  區(qū)別是:繼承Thread線程的代碼存放在Thread子類的run()方法中;

  實(shí)現(xiàn)Runnable線程的代碼存放在接口子類的run()方法中。

  2、什么是鎖對象?如何創(chuàng)建?如何獲得?

  每個(gè)Java對象都有一個(gè)鎖對象,而且只有一把鑰匙;

  可以使用this關(guān)鍵字作為鎖對象,也可以使用所在類的字節(jié)碼文件對應(yīng)的Class對象作為鎖對象;

  可以通過:類名.class 或者 對象.Class() 獲得。

  3、同步的使用?

  只能同步方法(代碼塊),不能同步類或者變量。

  4、如何解決《生產(chǎn)者與消費(fèi)者》的問題?

  可以通過一個(gè)標(biāo)記,表示數(shù)據(jù)的存儲(chǔ)空間狀態(tài)。

  【代碼如下:】

  pulibc class Demo{

  public static void main(String[] args){

  Persion p = new Person();

  Producer pro = new Prodecer();

  Consumer con = new Consumer();

  Thread t1 = new Thread(pro,"生產(chǎn)者");

  Thread t2 = new Thread(con,"消費(fèi)者");

  t1.start();

  t2.start();

  }

  }

  // 使用Person作為數(shù)據(jù)存儲(chǔ)空間

  class Person{

  String name;

  String gender;

  boolean flag = false;

  public synchronized void set(String name,String gender){

  if(flag){

  try{

  wait();

  }catch(InterruptedException e){

  e.printStackTrace();

  }

  }

  this.name = name;

  this.gender = gender;

  flag = true;

  notify();

  }

  public synchronized void read(){

  if(!flag){

  try{

  wait();

  }catch(InterruptedException e){

  e.printStackTrace();

  }

  }

  System.out.println("name:"+this.name+"----gender:"+this.gender);

  flag = false;

  notify();

  }

  }

  // 生產(chǎn)者

  class Producer implements Runnable{

  Person p;

  public Producer(){

  }

  public Producer(Person p ){

  this.p = p;

  }

  public void run(){

  int i = 0;

  while(trues){

  if(i%2=0){

  p.set("jack","man");

  }else{

  p.set("小麗","女");

  }

  i++;

  }

  }

  }

  // 消費(fèi)者

  class Consumer implements Runnable{

  Person p;

  public Consumer(){

  }

  public Consumer(Person p){

  this.p = p;

  }

  public void run(){

  while(true){

  p.read();

  }

  }

  }

  5、在Object類中,wait()和sleep()有什么卻別?

  wait() 是Object中的方法,表示:釋放資源,釋放鎖。

  sleep()是Thread中的方法,表示:釋放資源,不釋放鎖。

  6、為什么定義了notify(),還要再定義notifyAll()?

  因?yàn)槿绻挥胣otify()的話,容易出現(xiàn)只喚醒本方線程的情況,導(dǎo)致程序中的所有線程都在等待。



作者:黑馬程序員JavaEE培訓(xùn)學(xué)院

首發(fā): http://java.itheima.com

分享到:
在線咨詢 我要報(bào)名
和我們在線交談!