java中的多线程来看一看基础了

 

一  引言 :

           进程是一个正在执行中的程序,每个进程执行都有一个执行顺序,或执行路径;

           线程是进程中的内容,是进程中独立的控制单元;

           线程控制着进程的执行,或者是一个控制单元;

           一个进程中至少有一个线程;

 

二  如何创建线程

1.第一种方式为:

将类声明为Thread的子类,该子类应重写Thread类的run方法

例如:


class TestChildThread extends Thread{

 
    @Override
    public void run() {
        super.run();
    }
}

 

创建好子线程后,我们接下来启动使用它

class Test { 
    
      public static void main(String[] args) {

               //创建线程
             TestChildThread d = new TestChildThread(); 
               //启动
             d . start();

 }}

 

 

 2. 第二种方式是实现 Runnable接口,并重写Thread的run方法

 

 

class  RunnableDemo implements Runnable{
    @Override
    public void run() {
    }
}

class TestRunnableClass{
    public static void main(String[] args)
    {
        RunnableDemo  runnableDemo  = new  RunnableDemo();
        Thread  t = new  Thread(runnableDemo);
        t . start();
    }
}

 

 

 

注:  1. 定义类实现Runable接口来创建线程

         2. 覆盖 Runable 中run方法,将要执行的代码放入;

         3. 通过 Thread 类建立线和对象 

         4.将 Runnable接口子类对象作为实际参数传递给Thread类的构造函数中

         5.调用 Thread类的 start  方法 开户线程 

 注: 两种创建线程方式的区别:

        实现方式的好处,了单继承的局限性

       在定义线程时,建议使用实现类

       继承Thread: 线程代码存放在Thread类的run方法中

       实现Runable,线程将代码存放在接口的子类run方法中

 

3.注  :  在某一个时刻,只能有一个程序在运行;

              在多线程中,有一个特性:随机执行;

              d . run();是调用类Demo类中的run方法,而未启动线程

 

      4.为什么要重写run方法?

     将自定义代码存储在run方法中,让线程运行;

   例:

  

class ThreadDemos1 extends Thread
{
    public void run()
    {
        for(int x =0;x<10;x++)
        {
            System.out.println(this.getName()+" " + x);
        }
    }
}

//其中   this.getName  是获得线程的名称


class ThreadDemos2 extends Thread
{
    ThreadDemos2(String name)
    {
        super(name);
    }
    public void run()
    {
        for(int x =0;x<10;x++)
        {System.out.println(this.getName()+" " + x);
        }
    }
}


建立测试类

 

 

public class TestDemo {
    public static void main(String[] args) {
        ThreadDemos1  d1 = new ThreadDemos1();
        d1.start();
        ThreadDemos2  d = new ThreadDemos2("one");
        d.start();
    }
}

 

 

 

 

 

 

三  多线程运行状态

 

                                   阻塞状态

                                           |

线程建立——(start())——运行————sleep()————冻结

                                           |

                                        stop                                

 

四  自定义线程名称:

 

        ** 线程都有自己的名称 : Thread-标号  ,,  标号是从0开始的;

        **  获得线程名称的方法 : this.getName();     Thread.currentThread().getName()

        **  可以在线程初始化始时对线程命名;

 

       1.在线程初始化时候对其命名

 

 

class Demoss extends Thread
            {
          public void run()
              {
              for(int x =0;x<10;x++)
                   {
                System.out.println(this.getName()+" " + x);
                   }
               }
     }

public class TestDemo {

                  public static void main(String[] args) {

                  Demoss  d1 = new Demoss("one");
                                d1.start();

                 
}
}

 

 2. 可以使用构造函数对其重命名;

 

 

 
class Demos extends Thread
           {
           Demos(String name)
           {
                  super(name);
            }
           public void run()
          {
            for(int x =0;x<10;x++)
                 {
                 System.out.println(this.getName()+" " + x);
                   }
           }
   }

  public class TestDemo {

                  public static void main(String[] args) {

                  Demos  d1 = new Demos("one");
                                d1.start();


  }
}

 

 

五 多线程的安全问题

    1.同步 代码块

java对于多线程的安全问题,提供了专业的解决方式,就是  使用同步代码块,

结构         

   synchronized(对象)

                  {

                 被同步的代码

                  }

 

 

例如一个售票例子

总共1000张票   四个售票机

package test;
        public class TestDeoo {

           public static void main(String[] args) {


            Ticket  t = new Ticket();


            Thread  t1 = new Thread(t);
            Thread  t2 = new Thread(t);
            Thread  t3 = new Thread(t);
            Thread  t4 = new Thread(t);
                t1.start();
                t2.start();
                t3.start();
                t4.start();
         }
     }

class Ticket implements Runnable{
       private int tick=1000;
       Object obj = new Object();
       public void run(){
            while(true){
            synchronized(obj){
                           if(tick>0){
    "                                 try{Thread.sleep(10);}catch(Exception e){ };
                                }      <pre name="code" class="java">


System.out.println(Thread.currentThread().getName()+"sale"+tick--); } } }}

 

 

 

 

 

     2.同步代码块原理:

   例如有两个线程,当线程0获得CPU的执行权后,会读到synchronized代码块, 判断,然后会获得进入许可,继续执行下面的代码,随后synchronized 关闭入口,读到  stop时,线程结束,此时入口开放,等待下一线程的进入执行。。。。。。。。。。

     3.使用同步代码块的前提

   <1> 必须有两个或者两个以上的线程

   <2> 必须是多个线程使用同一个锁

     4.同步代码块的好处

    解决了线程的安全问题

      5.同步代码块的弊端

   多个线程要判断锁,较为消耗资源

六 同步函数

 

 

public class StringDemo {

	public static void main(String[] args) {
		Cuss c = new Cuss();
		Thread t = new Thread(c);
		Thread t2 = new Thread(c);
		t.start();
		t2.start();
	}
}

class Bank {
	private int sum;
	Object obj = new Object();

	public void add(int x) {
		synchronized (obj) {
			sum = sum + x;
			try {
				Thread.sleep(10);
			} catch (Exception e) {
			}
			System.out.println("sum " + sum);
		}
	}
}

class Cuss implements Runnable {
	private Bank b = new Bank();

	public void run() {
		for (int x = 0; x < 3; x++) {
			b.add(100);
			System.out.println(Thread.currentThread().getName());
		}
	}
}

 

 

 

 

 

 

使用同步函数形式来写出上述问题

class Banks {
	private int sum;
	Object obj = new Object();

	public synchronized void add(int x) {

		sum = sum + x;
		try {
			Thread.sleep(10);
		} catch (Exception e) {
		}
		System.out.println("sum " + sum);

	}
}

class Cuss implements Runnable

{
	private Banks b = new Banks();

	public void run() {
		for (int x = 0; x < 3; x++) {
			b.add(100);
			System.out.println(Thread.currentThread().getName());
		}
	}
}

public class stringDemo {

	public static void main(String[] args) {
		Cuss c = new Cuss();
		Thread t = new Thread(c);
		Thread t2 = new Thread(c);
		t.start();
		t2.start();
	}
}

 

七  单例设计模式

 

       1.   饿汉式

 

class Single {
	private static final Single s = new Singles();
	private Single() {
	}
	public static Single getInstanceP
	{
		return s;
	}
}

 

 

 

 

     2. 懒汉式

class Single {

	private static Single s = null;

	private Single() {
	}

	public static Single getInstance() {

		if (s == null) {

			synchronized (Single.class) {

				if (s == null) {
					s = new Single();
				}
			}
		}
		return s;
	}
}

 

 

 


                     

 

 

 

线程间的通讯

 

 线程间的的通讯,其实就是多个线程在操作同一个资源;但是操作的动作不同的资源

 

新建一个资源:

 

 

class Res
{
        String name;
        String sex; 

}

 

 

 

 

 

创建一个输入线程类:   输入与输出线程要操作同一个资源

 

class Input implements Runnable
{
        Res  r;
        Input(Res r)
        {
             this.r=r;
         }
        public void run()
         {
             boolean b =true;
             while(true)
             {
                 if(b)
                    {
                        r.name="lishi";
                        r.sex="man";
                        b = false;
                     }
                  else
                     {
                        r.name="李四";
                        r.sex="男";
                        b = true;
                     }
             }
        }
}

 


新建一个输出线程:  输入线程与输出线程操作的是同一个资源

 

 

 

class Output implements Runnable
{
         Res  r;


         Output(Res r)
         {
              this.r=r;
         }

         public void run()
         {
            while(true)
             {
                System.out.println(r.name);
             }
          }
}

 

 

 

 

 

新建一个测试类

 

 public class TestDemo {

       public static void main(String[] args) 

        {


               Res  r = new Res();
               Input in = new Input(r);
               Output out = new Output(r);

              Thread t = new Thread(in );
              Thread tl = new Thread(out);
                              t.start();
                              tl.start();
        }
}



 

 

这个程序的输出结果应该为  lishi  man

                                      李四   男

                                      。。。。。

测试一下,会出现乱码现象,如果要修改安全问题,就应该使用同步代码块

 

 

class Res
{
         String name;
         String sex; 

}
class Input implements Runnable
{
         Res  r;
         Input(Res r)
         {
                  this.r=r;
          }
          public void run()
          {
                  boolean b =true;
                  while(true)
                       {
                        synchronized(r)
                            {
                                    if(b)

                                       {
                                             r.name="lishi";
                                             r.sex="man";
                                             b = false;
                                      }
                                   else
                                      {
                                             r.name="李四";
                                             r.sex="男";
                                             b = true;
                                       }
                              }
                    }
         }
}

 

 

 

 

 

class Output implements Runnable
{
             Res  r;


             Output(Res r)
              {
                     this.r=r;
              }

             public void run()
               {

                    synchronized(r)
                         {
                    while(true)
                                 {
                           
                                     System.out.println(r.name+"  "+r.sex);
                                 }
                          }
               }
}

 

 

 

这样的话就解决了线程间的安全问题了

 

线程间的等待唤醒机制

新建一个资源

 

class Res
{
    String name;
    String sex; 
    boolean bo =  false;

}

 

class Input implements Runnable
{
    Res  r;
    Input(Res r)
     {
          this.r=r;
     }
    public void run()
     {
          boolean b =true;
          while(true)
         {
             synchronized(r)
              {
                if(r.bo)
                   try{r.wait();}catch(Exception e){}
                if(b)
                   {
                     r.name="lishi";
                     r.sex="man";
                     b = false;
                   }
                else
                   {
                     r.name="李四";
                     r.sex="男";
                     b = true;
                   }
                     r.bo =true ; 
                     r.notify();
              }
        }
   }
}

 

 

 

class Output implements Runnable
{
          Res  r;


         Output(Res r)
          {
             this.r=r;
          }

         public void run()
          {
            while(true)
             {
               synchronized(r)
                {
                  if(!r.bo)
                     try{r.wait();}catch(Exception e){}
                     System.out.println(r.name+"  "+r.sex);
                     r.bo=false;
                     r.notify();
                }
             }
        }
}

 

 

 

 

 

 

 

public class StringDemo {


public static void main(String[] args) 

{
           Res  r = new Res();
           Input in = new Input(r);
           Output out = new Output(r);

            Thread t = new Thread(in );
            Thread tl = new Thread(out);
           t.start();
           tl.start();

}
}

 

 

 

 

 

输出结果为

李四  男
lishi  man
李四  男
lishi  man
李四  男
lishi  man
李四  男
lishi  man
李四  男
lishi  man
李四  男
lishi  man
李四  男
lishi  man
李四  男
lishi  man
李四  男

 

 

注  :  wait  :

           notify()

           notifyAll()

 

都使用在同步中,因为要对持有监视器的线程操作,所以要使用在同步中,因为只有 同步才具有锁;

为什么这些操作线程的方法要定义在object 类中呢?

因为这些方法在操作同步线程中,都必须要标识它们所操作线程的锁,只有同一个锁上的被等待线程,可以被同一个锁上的notify唤醒,不可以对不同锁中的线程进行唤醒,也就是说,等待和唤醒必须是同一个锁,而锁可以是任意对象,所以可以被任意对象调用的方法定义在Object类中

 

优化后的代码

 

public class TestDemo {


public static void main(String[] args) {
         Resi  r = new Resi();
         new Thread(new Inputi(r)).start();
         new  Thread(new  Outputi(r)).start();
   }
}
class Resi
{
    String name;
    String sex; 
    boolean bo =  false;
    public synchronized void set(String name ,String sex)
    {
      if(bo)
           try{this.wait();}catch(Exception e){}
      this.name = name;
      this.sex = sex;
      bo = true ;
      this.notify();
     }
    public synchronized void out()
    {
      if(!bo)
         try{this.wait();}catch(Exception e){}
      System.out.println(name +"  "+sex);
      bo = false;
      this.notify();
     }
}


class Inputi implements Runnable
{
       Resi  r;
       Inputi(Resi r)
       {
           this.r = r;
        }

        public void run()
        {
            boolean b =true;
            while(true)
             {
                if(b)
                {
                  r.set("lishi","man");
                  b = false;
                }
                else
                {
                r.set("李四","男");
    b = true;
              }
         }
       }
}

class Outputi implements Runnable
{
        Resi  r;
        Outputi(Resi r)
      {
        this.r = r;
       }
       public void run()
      {
        while(true)
           r.out();
        }



 

 

 

 

 

生产者与消费者    线程间的通信

 

 

public class StringDemo {


 public static void main(String[] args) {
        Resourced r = new Resourced();
        new Thread(new Producerd(r)).start();//1
        new Thread(new Producerd(r)).start();//2
        new Thread(new Consumerd(r)).start();//3
        new Thread(new Consumerd(r)).start();//4
   }
}

 

 

 



/*
 * 生产一个,消费一个*/
class Resourced
{
    private String name;
    private int count  = 1;
    private boolean flag = false;
    public synchronized void set(String name)
    {
       while(flag)
       try{wait();}catch(Exception e){}
       this.name = name+"  "+count++;
        System.out.println(Thread.currentThread().getName()+"生产者,,,," + this.name);
       flag = true;
       this.notifyAll();
     }

   public void out(){

    while(!flag)
    try{wait();}catch(Exception e){}

    System.out.println(Thread.currentThread().getName()+"消费者    " + this.name);
    flag = false;
     this.notifyAll();
   }
  }

 

 

 

 

 

 

 

class Producerd implements Runnable
{
        private Resourced res ;
        Producerd(Resourced res)
       {
            this.res = res;
        }
        public void run()
        {
            while(true)
            '7B
              res.set("商品");
            }
        }
}

 

 

 

 

 

 

class Consumerd implements Runnable
{
      private Resourced res;
     Consumerd(Resourced res)
    {
        this.res = res;
     }
     public void run()
     {
        while(true)
        {
           res.out();
        }
    }
}

 

 

 

 

 

早起的年轻人 CSDN认证博客专家 移动开发 项目管理 Java
只要用心去做,每一件事情还是有可能成功的,当然成功是没有界限的,只不过是达到自己心里的那个目标,公众号:我的大前端生涯,一个爱喝茶的程序员,通常会搞搞SpringBoot 、Herbinate、Mybatiys、Android、iOS、Flutter、Vue、小程序等.
©️2020 CSDN 皮肤主题: 代码科技 设计师:Amelia_0503 返回首页