• 线程与进程


    线程就是程序中单独顺序的流控制。线程本身不能运行,它只能用于程序中。

    线程是程序内的顺序控制流,只能使用分配给程序的资源和环境。

     

    多线程编程的目的,就是最大限度地利用CPU资源。

    多线程:指的是在单个程序中可以同时运行多个不同的线程执行不同的任务。

     

     

    进程:运行一个程序就会启动一个进程,本质是一个执行的程序。(程序是静态的,而进程是动态的)

     

    单线程:当程序启动时,就自动产生一个线程,主方法main就在这个主线程上运行。

     

    多线程

    一个进程可以包含一个或多个线程

    一个程序实现多个代码同时交替运行就需要产生多个线程

    CPU随机的抽出时间,让我们的程序一会做这件事情,一会做另外一件事情。

     

     

    进程与线程的区别

    进程是重量级的任务,需要分配给它们独立的地址空间。进程间通信是昂贵的受限的

    线程共享相同的地址空间并且共同分享同一个进程。线程间通信是便宜的,转换也是低成本 的。

     

     

    线程的实现:

    第一种方式:继承Thread类民,然后重写run方法

    public class ThreadTest

    {

        public static void main(String[] args)

        {

           Thread1 t1 = new Thread1();

           Thread2 t2 = new Thread2();

          

           t1.start();

           t2.start();

        }

    }

     

    class Thread1 extends Thread

    {

        @Override

        public void run()

        {

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

               System.out.println("welcome" + i);

        }

    }

     

    class Thread2 extends Thread

    {

        @Override

        public void run()

        {

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

               System.out.println("hello" + i);

        }

    }

     

     

    第二种方式:实现Runnable接口,然后实现run方法。

    public class ThreadTest2

    {

        public static void main(String[] args)

        {

           Thread t1 = new Thread(new MyThread1());

     

           t1.start();

     

           Thread t2 = new Thread(new MyThread2());

     

           t2.start();

     

           System.out.println(t1.getId() + t1.getName());

     

           System.out.println(t2.getId() + t2.getName());

        }

    }

     

    class MyThread1 implements Runnable

    {

        @Override

        public void run()

        {

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

           {

               System.out.println("hello-" + i);

           }

        }

    }

     

    class MyThread2 implements Runnable

    {

        @Override

        public void run()

        {

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

           {

               System.out.println("welcome-" + i);

           }

        }

    }

     

    将我们希望线程执行的代码放到run方法中,然后通过start方法来启动线程,strart方法首先为线程执行准备好系统资源中,然后再去调用run方法。

     

    一个进程至少要有一个线程

     

    对于单核CPU来说,某一时刻只能有一个线程在执行(微观串行),从宏观角度来看,多个线程在同时执行(宏观并行)。

     

    对于双核或多核的CPU来说,可以真正做到微观并行。

     

    Thread类也实现了Runnable接口,因此实现了Runnable接口中的run方法。

     

    当生成一个线程对象时,如果没有为它设定名字,线程对象会使用如下形式取名:

    Thread-numbernumber是自动增加的,并被所有的Thread对象所共享(因为它是Static的成员变量)

     

    Thread类的run方法什么也没做,只有我们传入一个继承Thread类或实现Runnable接口的

    类的实例时,它才具有意义。

    也就是说Thread类的run方法中执行的代码,是我们编写的run方法代码。

     

    线程的消亡不能通过调用一个stop()命令,而是让run方法自然结束。

    一般用如下方式结束线程

    public class MyThread implements Runnable

    {

        private boolean flag = true;

        public void run()

        {

           while(flag)

           {

               if(...)

               {

                  StopRunning();

               }

           }

        }

       

        public void StopRunning()

        {

           flag = false;

        }

    }

     

     

    线程的生命周期:一个线程从创建到消亡的过程。

    1.创建状态

    当用new操作符创建时

    处于创建状态的线程只是一个空的线程对象,系统不为它分配资源。

     

    2.可运行状态

    执行线程的start方法,为线程分配必须的系统资源,安排其运行,并调用run方法,此时处于Runnable状态

    这一状态并不是运行中状态(running),因为线程也许实际上并未真正运行。

     

    3.不可运行状态

    下列情况的发生,会使线程从运行状态转到不可运行状态:

    调用了sleep方法

    调用wait方法等待特定条件的满足。

    线程输入/输出阻塞

     

    返回可运行状态:

    处于睡眠状态的线程在指定的时间过去后

    调用notify()notifyAll方法通知等待线程条件的改变。

    如果线程是因为输入/输出阻塞,等待输入/输出完成

     

    4.消亡状态

    Run方法执行结束后,该线程自然消亡。

     

     

    线程的优先级可以用setPriority()方法来改变,一般是1-10之间的正整数。

     

    线程的调度策略

    线程调度器选择优先级最高的线程运行,但是,如果发生以下情况,就会终止线程的运行:

    1.线程体中调用了yield方法,让出了对cpu的占用权

    2.线程体中调用了sleep方法,使线程进入睡眠状态

    3.线程由于I/O操作受阻塞

    4.另一个更高优先级的线程实现

    5.在支持时间片的系统中,该线程的时间片用完。

     

    public class ThreadTest3

    {

        public static void main(String[] args)

        {

           Runnable r = new HelloThread();

     

           Thread t1 = new Thread(r);

          

           r = new HelloThread();//引用的不是同一个对象,线程之间互不影响。

              

           Thread t2 = new Thread(r);

     

           t1.start();

           t2.start();

     

        }

    }

     

    class HelloThread implements Runnable

    {

        int i;//当不同的线程引用同一个成员变量时,其中一个线程对它的修改会反映到其他线程上

     

        @Override

        public void run()

        {

           int i = 0;//当不同的线程对局部变量进行修改时,由于每个线程引用的只是它的一份拷贝,所以互不影响

          

           while (true)

           {

               System.out.println("hello-" + (i++));

     

               try

               {

                  Thread.sleep((long) (Math.random() * 1000));

               }

               catch (Exception e)

               {

                  e.printStackTrace();

               }

     

               if (50 == i)

               {

                  break;

               }

           }

        }

    }

     

     

    多线程的同步

     

    1.为什么要引入同步机制

    在多线程环境中,可能会出现两个或多个线程试图同时访问一个有限的资源。

    必须对这种潜在的资源冲突进行预防

     

    解决方法:在线程使用一个资源时为其加锁即可。这样其他线程就无法访问这个资源,直到锁被解开。

     

    2.怎么实现同步

    方法声明中加上synchronized关键字,当方法被调用时,对象就会被锁定。

    说明:

    synchronized方法执行完或发生异常时,会自动释放锁。

    synchronized保护的数据应该是私有的

     

    一个银行取钱的例子。

    public class FetchMoney

    {

        public static void main(String[] args)

        {

           Bank bank = new Bank();

     

           Thread t1 = new MoneyThread(bank);

           Thread t2 = new MoneyThread(bank);

     

           t1.start();

           t2.start();

        }

    }

     

    class Bank

    {

        private int money = 1000;

     

        //synchronized关键字表示将对象上锁,只有在一个线程执行完毕后,另一线程才能去访问该对象。这样就避免了同时并发的发生。

        public synchronized int getMoney(int number)

        {

           if (number < 0)

           {

               return -1;

           }

           else if (number > money)

           {

               return -2;

           }

           else if (money < 0)

           {

               return -3;

           }

           else

           {

               try

               {

                  Thread.sleep(1000);// 当让线程睡眠时,第一个线程暂时没起作用,那么第二个线程进来以后,前面的检查就跳过去了

               }

               catch (InterruptedException e)

               {

                   e.printStackTrace();

               }

     

               money -= number;//线程同时醒过来,并起作用。出现同时取钱效果。

     

               System.out.println("Left money : " + money);

     

               return money;

           }

        }

    }

     

    class MoneyThread extends Thread

    {

        private Bank bank;

     

        public MoneyThread(Bank bank)

        {

           this.bank = bank;

        }

     

        @Override

        public void run()

        {

           System.out.println(bank.getMoney(800));

        }

    }

     

     

    public class ThreadTest4

    {

        public static void main(String[] args)

        {

           //有序执行和无序执行的关键:有几个对象?锁的是谁?

           Example e = new Example();

          

           Thread t1 = new TheThread(e);

           

           e = new Example();

          

           Thread t2 = new TheThread2(e);

          

           t1.start();

           t2.start();

        }

    }

     

    class Example

    {

        //synchronized关键字表示将对象上锁,不管对象里有多少个synchronized修饰的方法,

        //都会先执行一个线程,这个线程执行完毕后,才执行第二个线程,也就是说不存在同时执行的可能。

        public synchronized void execute()

        {

           for (int i = 0; i < 20; i++)

           {

               try

               {

                  Thread.sleep((long) (Math.random() * 500));

               }

               catch (InterruptedException e)

               {

                  e.printStackTrace();

               }

               System.out.println("hello" + i);

           }

        }

       

        //当一个方法用synchronized static去修饰时,表示对对象所对应的class本身上锁。

        public synchronized static void execute2()

        {

           for (int i = 0; i < 20; i++)

           {

               try

               {

                  Thread.sleep((long) (Math.random() * 500));

               }

               catch (InterruptedException e)

               {

                  e.printStackTrace();

               }

               System.out.println("world" + i);

           }

        }

    }

     

    class TheThread extends Thread

    {

        private Example example;

     

        public TheThread(Example example)

        {

           super();

           this.example = example;

        }

     

        @Override

        public void run()

        {

           this.example.execute();

        }

    }

     

    class TheThread2 extends Thread

    {

        private Example example;

     

        public TheThread2(Example example)

        {

           super();

           this.example = example;

        }

     

        @Override

        public void run()

        {

           this.example.execute2();

        }

    }

     

    使用synchronized{ }

    public class ThreadTest5

    {

        public static void main(String[] args)

        {

           // 有序执行和无序执行的关键:有几个对象?锁的是谁?

           Example1 e = new Example1();

     

           Thread t1 = new TheThread3(e);

     

           e = new Example1();

     

           Thread t2 = new TheThread4(e);

     

           t1.start();

           t2.start();

        }

    }

     

    class Example1

    {

        public synchronized void execute()

        {

           //实际开发可以选择采用synchronized语句块,可以对线程的访问控制得更加细粒度

           synchronized (this)

           {

               for (int i = 0; i < 20; i++)

               {

                  try

                  {

                      Thread.sleep((long) (Math.random() * 500));

                  }

                  catch (InterruptedException e)

                  {

                      e.printStackTrace();

                  }

                  System.out.println("hello" + i);

               }

           }

        }

     

        public void execute2()

        {

           synchronized (this)

           {

               for (int i = 0; i < 20; i++)

               {

                  try

                  {

                      Thread.sleep((long) (Math.random() * 500));

                  }

                  catch (InterruptedException e)

                  {

                      e.printStackTrace();

                  }

                  System.out.println("world" + i);

               }

           }

        }

    }

     

    class TheThread3 extends Thread

    {

        private Example1 example;

     

        public TheThread3(Example1 example)

        {

           this.example = example;

        }

     

        @Override

        public void run()

        {

           this.example.execute();

        }

    }

     

    class TheThread4 extends Thread

    {

        private Example1 example;

     

        public TheThread4(Example1 example)

        {

           this.example = example;

        }

     

        @Override

        public void run()

        {

           this.example.execute2();

        }

    }

     

    线程间的相互作用

     

    使用Wait()notify()来控制线程间的相互作用,使它们相互协作,以防止死锁。

     

    这两个方法都定义在Object,而且是final的,因此会被所有的java类所继承且不能被重写。

     

    这两个方法要求在调用时线程应该已经获得了对象的锁,因此对这两个方法的调用需要放在synchronized方法或块当中。

     

    当线程执行了wait方法时,它会释放掉对象的锁。

     

    Notify通知另外一个线程时是任意的,你无法决定它所通知的对象。

     

    另一个会导致线程暂停的方法就是sleep方法,这会导致线程睡眠指定的毫秒数,但线程在睡眠过程中是不会释放掉对象的锁的。

     

    Public class ThreadTest6

    {

        public static void main(String[] args)

        {

           Sample sample = new Sample();

          

           Thread t1 = new IncreaseTeread(sample);

           Thread t2 = new DecreaseThread(sample);

          

           Thread t3 = new IncreaseTeread(sample);

           Thread t4 = new DecreaseThread(sample);

          

           t1.start();

           t2.start();

           t3.start();

           t4.start();

        }

    }

     

    class Sample

    {

        private int number;

     

        public synchronized void increase() throws Exception

        {

        //这里要用while而不是if

           while (0 != number)

           {

               wait();

           }

     

           number++;

     

           System.out.println(number);

     

           notify();

        }

     

        public synchronized void decrease() throws Exception

        {

           while (0 == number)

           {

               wait();

           }

     

           number--;

     

           System.out.println(number);

     

           notify();

        }

    }

     

    class IncreaseTeread extends Thread

    {

        private Sample sample;

     

        public IncreaseTeread(Sample sample)

        {

           super();

           this.sample = sample;

        }

     

        @Override

        public void run()

        {

           for (int i = 0; i < 20; i++)

           {

               try

               {

                  Thread.sleep((long) (Math.random() * 1000));

     

                  sample.increase();

               }

               catch (Exception e)

               {

                  // TODO Auto-generated catch block

                  e.printStackTrace();

               }

           }

        }

    }

     

    class DecreaseThread extends Thread

    {

        private Sample sample;

     

        public DecreaseThread(Sample sample)

        {

           super();

           this.sample = sample;

        }

     

        @Override

        public void run()

        {

           for (int i = 0; i < 20; i++)

           {

               try

               {

                  Thread.sleep((long) (Math.random() * 1000));

     

                  sample.decrease();

               }

               catch (Exception e)

               {

                  // TODO Auto-generated catch block

                  e.printStackTrace();

               }

           }

        }

    }

     

     

    实际开发中如果遇到同时并发的问题,可以用java.util.concurrent包来进行处理。

     

    Wait pool 和 lock pool


     

     

    基于多线程的单件模式

    public class Singleton

    {

        private static Singleton instance = null;

        private static volatile Object objHelper = new Object();

     

        private Singleton()

        {

     

        }

     

        public static Singleton getInstance()

        {

           synchronized(objHelper)

           {

               while(null == instance)

               {

                  try

                  {

                      Thread.sleep((long)(Math.random()*3000));

                  }

                  catch (InterruptedException e)

                  {

                      e.printStackTrace();

                  }

                 

                  instance = new Singleton();

               }

           }

           return instance;

        }

     

        public static void main(String[] args)

        {

           new MyThread().start();

           new MyThread().start();

        }

    }

     

    class MyThread extends Thread

    {

        @Override

        public void run()

        {

           System.out.println(Singleton.getInstance());

        }

    }

     

  • 相关阅读:
    记录下我的阿里云centos服务器之路
    git-ftp 用git管理ftp空间
    标准插件写法
    函数防抖 主要用于限制高频触发事件函数的执行间隔
    js 各进制前缀 及 转换
    微信 小程序 canvas
    微信 小程序 drawImage wx.canvasToTempFilePath wx.saveFile 获取设备宽高 尺寸问题
    canvas画布在主流浏览器中的尺寸限制
    js的一些坑,持续增加,学习js应该注意的问题
    js => ES6一个新的函数写法
  • 原文地址:https://www.cnblogs.com/zfc2201/p/2143640.html
Copyright © 2020-2023  润新知