zoukankan      html  css  js  c++  java
  • JAVA多线程

    JAVA状态

    在Java当中,线程通常都有五种状态,创建、就绪、运行、阻塞和死亡。

      第一是创建状态。在生成线程对象,并没有调用该对象的start方法,这是线程处于创建状态。

      第二是就绪状态。当调用了线程对象的start方法之后,该线程就进入了就绪状态,但是此时线程调度程序还没有把该线程设置为当前线程,此时处于就绪状态。在线程运行之后,从等待或者睡眠中回来之后,也会处于就绪状态。

      第三是运行状态。线程调度程序将处于就绪状态的线程设置为当前线程,此时线程就进入了运行状态,开始运行run函数当中的代码。

      第四是阻塞状态。线程正在运行的时候,被暂停,通常是为了等待某个时间的发生(比如说某项资源就绪)之后再继续运行。sleep,suspend,wait等方法都可以导致线程阻塞。

      第五是死亡状态。如果一个线程的run方法执行结束或者调用stop方法后,该线程就会死亡。对于已经死亡的线程,无法再使用start方法令其进入就绪。

    同步的原理,同步的好处,弊端 ,同步的前提

    同步的原理:其实就是将需要同步的代码进行封装,并在该代码上加了一个锁。

    同步的好处,弊端:

    好处:使多线程处于能够安全的运行。

    弊端:在加了多线程之后,多个线程在对锁申请使用权的时候,会使CPU不断的切换,,这样做,会引起性能的降低。

    同步的前提:

    1. 必须要保证在同步中有多个线程。      因为同步中只有一个线程该同步是没有意义的。

    2. 必须要保证多个线程在同步中使用的是同一个锁。这是才称为 多个线程被同步了!

     线程常见问题

    线程阻塞

    1.Wait和Sleep的区别

    • 它们最大本质的区别是,Sleep()不释放同步锁,Wait()释放同步锁。

    • 还有用法的上的不同是:Sleep(milliseconds)可以用时间指定来使他自动醒过来,如果时间不到你只能调用Interreput()来强行打断;Wait()可以用Notify()直接唤起。

    • 这两个方法来自不同的类分别是Thread和Object

    • 最主要是Sleep方法没有释放锁,而Wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。

     2.Thread.sleep() 和Thread.yield()的异同

    • 相同 :Sleep()和yield()都会释放CPU。

    • 不同:Sleep()使当前线程进入停滞状态,所以执行Sleep()的线程在指定的时间内肯定不会执行;yield()只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。Sleep()可使优先级低的线程得到执行的机会,当然也可以让同优先级和高优先级的线程有执行的机会;yield()只能使同优先级的线程有执行的机会

     3.并发和并行的区别

    并发:是指在某个时间段内,多任务交替的执行任务。当有多个线程在操作时,把CPU运行时间划分成若干个时间段,再将时间段分配给各个线程执行。在一个时间段的线程代码运行时,其它线程处于挂起状。

    并行:是指同一时刻同时处理多任务的能力。当有多个线程在操作时,CPU同时处理这些线程请求的能力。

    区别就在于CPU是否能同时处理所有任务,并发不能,并行能。

     4.线程安全三要素

    • 原子性:Atomic包、CAS算法、Synchronized、Lock。

    • 可见性:Synchronized、Volatile(不能保证原子性)。

    • 有序性:Happens-before规则。

     5.如何实现线程安全

    • 互斥同步:Synchronized、Lock。

    • 非阻塞同步:CAS。

    • 无需同步的方案:如果一个方法本来就不涉及共享数据,那它自然就无需任何同步操作去保证正确性。

    6.保证线程安全的机制

      Synchronized关键字
      Lock
      CAS、原子变量
      ThreadLocal:简单来说就是让每个线程,对同一个变量,都有自己的独有副本,每个线程实际访问的对象都是自己的,自然也就不存在线程安全问题了。
      Volatile
      CopyOnWrite写时复制

     7.创建线程的方法

      继承Thread类

      public class ThreadCreateTest { 

        public static void main(String[] args) {
          new MyThread().start();
        }
      }

      class MyThread extends Thread {
        @Override
        public void run() {
          System.out.println(Thread.currentThread().getName() + "\t" + Thread.currentThread().getId());
        }
      }

      实现Runable接口

      public class RunableCreateTest {
        public static void main(String[] args) {
          MyRunnable runnable = new MyRunnable();
          new Thread(runnable).start();
        }
      }

      class MyRunnable implements Runnable {
        @Override
        public void run() {
          System.out.println(Thread.currentThread().getName() + "\t" + Thread.currentThread().getId());
        }
      }

      通过Callable和Future创建线程

      public class CallableCreateTest {
        public static void main(String [] args) throws Exception {
        // 将Callable包装成FutureTask,FutureTask也是一种Runnable
          MyCallable callable = new MyCallable();
          FutureTask futureTask = new FutureTask<>(callable);
          new Thread(futureTask).start();

          // get方法会阻塞调用的线程
          Integer sum = futureTask.get();
          System.out.println(Thread.currentThread().getName() + Thread.currentThread().getId() + "=" + sum);
        }
      }
      class MyCallable implements Callable<Integer> {
        @Override
        public Integer call() throws Exception {
          System.out.println(Thread.currentThread().getName() + "\t" + Thread.currentThread().getId() + "\t" + new Date() + " \tstarting...");
          int sum = 0;
          for (int i = 0; i <= 100000; i++) {
            sum += i;
          }
          Thread.sleep(5000);
          System.out.println(Thread.currentThread().getName() + "\t" + Thread.currentThread().getId() + "\t" + new Date() + " \tover...");
          return sum;
        }
      }

      Java提供四种线程池创建方式:

    • newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

    • newFixedThreadPool创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

    • newScheduledThreadPool创建一个定长线程池,支持定时及周期性任务执行。

    • newSingleThreadExecutor创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

  • 相关阅读:
    mysql数据库常用指令
    解决windows的mysql无法启动 服务没有报告任何错误的经验。
    “Can't open file for writing”或“operation not permitted”的解决办法
    启动Apache出现错误Port 80 in use by "Unable to open process" with PID 4!
    如何打开windows的服务services.msc
    常见的HTTP状态码 404 500 301 200
    linux系统常用的重启、关机指令
    (wifi)wifi移植之命令行调试driver和supplicant
    linux(debian)安装USB无线网卡(tp-link TL-WN725N rtl8188eu )
    alloc_chrdev_region申请一个动态主设备号,并申请一系列次设备号
  • 原文地址:https://www.cnblogs.com/cqyy/p/13963213.html
Copyright © 2011-2022 走看看