多线程

多线程

  1. 什么是线程?

    线程是操作系统能够进行运算调度的最小单位;它被包含在进程之中,是进程中的实际运作单位。

  2. 线程和进程有什么区别?

    线程是进程的子集,一个进程可以有很多线程,每条线程并行执行不同的任务。不同的进程使用不同的内存空间,所有的线程共享一片相同的内存空间。

  3. Java多线程的实现有哪些方法?

    1. 继承Thread类创建线程

      Thread类本质上是实现了Runnable接口的一个实例,代表一个线程的实例。启动线程的唯一方法就是通过Thread类的start()实例方法。start()方法是一个native方法,它将启动一个新线程,并执行run()方法。这种方式实现多线程很简单,通过自己的类直接extend Thread,并复写run()方法,就可以启动新线程并执行自己定义的run()方法。

      例如:

      public class MyThread extends Thread {
      	public void run() {
      		while(true) {
      			System.out.println(this.getName()+" running...");
      			try {
                      Thread.sleep(1000); // 休息1000ms
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
      		}
      	}
      	public static void main(String[]args) {
      		MyThread thread1 = new MyThread();
      		MyThread thread2 = new MyThread();
      		thread1.start();
      		thread2.start();
      	}
      }
       
      //执行结果
      Thread-1 running...
      Thread-0 running...
      Thread-1 running...
      Thread-0 running...
      Thread-1 running...
      Thread-0 running...
      Thread-1 running...
      Thread-0 running...
      Thread-1 running...
      Thread-0 running...
      Thread-1 running...
      Thread-0 running...
      
    2. 实现Runnable接口

      实现Runnable接口也是一种常见的创建线程的方式。使用接口的方式可以让我们的程序降低耦合度。Runnable接口中仅仅定义了一个方法,就是run。

      其实Runnable就是一个线程任务,线程任务和线程的控制分离,这也就是上面所说的解耦。我们要实现一个线程,可以借助Thread类,Thread类要执行的任务就可以由实现了Runnable接口的类来处理。 这就是Runnable的精髓之所在!

      例如:

      //集成Runnable接口定义任务类
      public class ThreadTask implements Runnable {
       
      	@Override
      	public void run() {
      			while(true) {
      			System.out.println(Thread.currentThread().getName()+" is running...");
      			try {
      	            Thread.sleep(1000);
      	        } catch (InterruptedException e) {
      	            e.printStackTrace();
      	        }
      		}
      	}
      }
       
       
      //在main方法中创建线程去完成该任务
      public class Main extends ThreadTask {
      	public static void main(String[]args) {
      		ThreadTask task = new ThreadTask();//新建任务类
      		Thread t1 = new Thread(task);
      		t1.start();
      		Thread t2 = new Thread(task);
      		t2.start();
      	}
      }
      
    3. 实现Callable接口

      与实现Runnable接口实现多线程类似,也有不同

      相同点:
      两者都可用来编写多线程程序;
      两者都需要调用Thread.start()启动线程;

      不同点:

      两者最大的不同点是:实现Callable接口的任务线程能返回执行结果;而实现Runnable接口的任务线程不能返回结果;
      Callable接口的call()方法允许抛出异常;而Runnable接口的run()方法的异常只能在内部消化,不能继续上抛;

      import java.util.concurrent.Callable;
       
      public class ThreadImplementsCallable implements Callable<Integer> {
        private int i;
         
        @Override
        public Integer call() throws Exception {
          for(; i < 100; i++){
            System.out.println(Thread.currentThread().getName() + " " + i);
          }
          return i;
        }
      }
      
    4. 通过线程池来实现多线程

      public class ThreadDemo05{
       
          private static int POOL_NUM = 10;     //线程池数量
       
          /**
           * @param args
           * @throws InterruptedException 
           */
          public static void main(String[] args) throws InterruptedException {
              // TODO Auto-generated method stub
              ExecutorService executorService = Executors.newFixedThreadPool(5);  
              for(int i = 0; i<POOL_NUM; i++)  
              {  
                  RunnableThread thread = new RunnableThread();
       
                  //Thread.sleep(1000);
                  executorService.execute(thread);  
              }
              //关闭线程池
              executorService.shutdown(); 
          }   
       
      }
       
      class RunnableThread implements Runnable  
      {     
          @Override
          public void run()  
          {  
              System.out.println("通过线程池方式创建的线程:" + Thread.currentThread().getName() + " ");  
       
          }  
      }
       
      执行结果
      通过线程池方式创建的线程:pool-1-thread-3  
      通过线程池方式创建的线程:pool-1-thread-4  
      通过线程池方式创建的线程:pool-1-thread-1  
      通过线程池方式创建的线程:pool-1-thread-5  
      通过线程池方式创建的线程:pool-1-thread-2  
      通过线程池方式创建的线程:pool-1-thread-5  
      通过线程池方式创建的线程:pool-1-thread-1  
      通过线程池方式创建的线程:pool-1-thread-4  
      通过线程池方式创建的线程:pool-1-thread-3  
      通过线程池方式创建的线程:pool-1-thread-2
      
  4. 用Runnable还是Thread?

Java不支持类的多重继承,但允许调用多个接口。所以如果要继承其他类,当然是调用Runnable接口更好。

  1. Thread类中的 start()和run()方法有什么区别?

    start()方法被用来启动新创建的线程,而且start()内部调用了run()方法,这和直接调用run()方法的效果不一样。当调用run()方法的时候,只会是在原来的线程中调用,没有新的线程启动,start()方法会启动新线程。

  2. volatile

    volatile是一个特殊的修饰符,只有成员变量才能使用它。保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这个新值对其他线程来说是立即可见的。

  3. 线程的五大状态

    新建状态:新建线程对象,并没有调用start()方法之前;

    就绪状态:调用start()方法之后线程就进入就绪状态,但是并不是说只要调用start()方法线程就马上变为当前线程,在变为当前线程之前都是为就绪状态。值得一提的是,线程在睡眠和挂起中恢复的时候也会进入就绪状态;

    运行状态:线程被设置为当前线程,开始执行run()方法。就是线程进入运行状态;

    阻塞状态:线程被暂停,比如说调用sleep()方法后线程就进入阻塞状态;

    死亡状态:线程执行结束。

  4. notify和notifyAll的区别

    • 如果线程调用了对象的 wait()方法,那么线程便会处于该对象的等待池中,等待池中的线程不会去竞争该对象的锁
    • 当有线程调用了对象的 notifyAll()方法(唤醒所有 wait 线程)或 notify()方法(只随机唤醒一个 wait 线程),被唤醒的的线程便会进入该对象的锁池中,锁池中的线程会去竞争该对象锁。也就是说,调用了notify后只有一个线程会由等待池进入锁池,而notifyAll会将该对象等待池内的所有线程移动到锁池中,等待锁竞争。
    • 优先级高的线程竞争到对象锁的概率大,假若某线程没有竞争到该对象锁,它还会留在锁池中,唯有线程再次调用 wait()方法,它才会重新回到等待池中。而竞争到对象锁的线程则继续往下执行,直到执行完了 synchronized 代码块,它会释放掉该对象锁,这时锁池中的线程会继续竞争该对象锁。
  5. 多线程面试题集合

https://www.cnblogs.com/xiaowangbangzhu/p/10443289.html

上一篇:SQL Server Join


下一篇:batch normalization手写代码