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

    一、是什么

    1、进程:正在运行中的程序

    2、线程:进程中的最小执行单元

    3、线程状态:

    1、新建状态(New):新创建了一个线程对象。
    2、就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
    3、运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
    4、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
    (一)、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。(wait会释放持有的锁)
    (二)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
    (三)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。(注意,sleep是不会释放持有的锁)
    5、死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

    ————————————————
    版权声明:本文为CSDN博主「Evankaka」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/evankaka/article/details/44153709

     4、创建线程的三种方式

    •  自定义类继承 Thread 类 
    •  实现Runnable 接口 (基本上都用这个)
    •     实现Callable 接口 (要考虑线程执行体的返回值时用)

    5、线程运行方法,最终都是调用各自实现的run方法

    •  new Thread().start();
    •     executor.execute(thread1);
    •     executor.submit(thread1);

    二、怎么用

    1、直接用Thread

    package com.jc.thread.impl;
    
    public class ThreadTest extends Thread {
    
    	private String index;
    
    	public ThreadTest() {
    		super();
    	}
    
    	public ThreadTest(String index) {
    		super();
    		this.index = index;
    	}
    
    	public void run() {
    		System.out.println(Thread.currentThread().getName() + " --- " + index
    				+ "开始执行,循环输出5次index");
    		for (int i = 0; i < 5; i++) {
    			System.out.println(index + " -- 第" + i + "次执行");
    		}
    		System.out.println(Thread.currentThread().getName() + "执行完毕");
    	}
    
    	public String getIndex() {
    		return index;
    	}
    
    	public void setIndex(String index) {
    		this.index = index;
    	}
    
    }
    

      运行

    public static void testThread() {
    		ThreadTest thread1 = new ThreadTest();
    		thread1.setIndex("A");
    
    		ThreadTest thread2 = new ThreadTest("B");
    
    		thread1.start();
    		thread2.start();
    
    	}
    

     结果

    2、实现Runnable 接口 

    package com.jc.thread.impl;
    
    public class RunableTest implements Runnable {
    
    	private String index;
    
    	public RunableTest() {
    		super();
    	}
    
    	public RunableTest(String index) {
    		super();
    		this.index = index;
    	}
    
    	@Override
    	public void run() {
    		System.out.println(Thread.currentThread().getName() + " --- " + index
    				+ "开始执行,循环输出5次index");
    		for (int i = 0; i < 5; i++) {
    			System.out.println(index + " -- 第" + i + "次执行");
    		}
    		System.out.println(Thread.currentThread().getName() + "执行完毕");
    	}
    
    	public String getIndex() {
    		return index;
    	}
    
    	public void setIndex(String index) {
    		this.index = index;
    	}
    
    }
    

      运行

    public static void testRunable() {
    		RunableTest thread1 = new RunableTest();
    		thread1.setIndex("A");
    
    		RunableTest thread2 = new RunableTest("B");
    
    		new Thread(thread1).start();
    		new Thread(thread2).start();
    
    		/**
    		 * 可以给即将启动的线程命名
    		 */
    		// new Thread(thread1,"1st_thread").start();
    		// new Thread(thread2,"2nd_thread").start();
    
    		/**
    		 * 实现runable接口的实现类中的run()方法被当做普通方法调用,不会启动别的线程,而是在main线程中顺序执行
    		 * 也就是没达到多线程的目的
    		 */
    		// thread1.run();
    		// thread2.run();
    
    		/**
    		 * Thread对象的start()方法,最终执行的还是thread 对象的run方法
    		 * 如果Thread对象重写了run,而且重写的run里面没有要执行Thread对象属性中的
    		 * Runnable对象的run方法,那就不会执行runable里实现的run方法
    		 * 
    		 * Thread 也是实现了runable接口的实现类 Thread 的 run方法
    		 * 
    		 * @Override public void run() { if (target != null) { target.run(); } }
    		 * 
    		 */
    		/*
    		 * new Thread(new Runnable(){
    		 * 
    		 * @Override public void run() {
    		 * System.out.println("runable 的线程执行体执行了");//不打印 }
    		 * 
    		 * }){ public void run() {
    		 * System.out.println("Thread 的线程执行体执行了");//只输出这条 //调用父类Thread 的
    		 * run方法,会执行 runable 实现类实现的方法 super.run(); } }.start();
    		 */
    
    	}
    

     

    3、实现Callable 接口

    package com.jc.thread.impl;
    
    import java.util.concurrent.Callable;
    
    public class CallableTest implements Callable<String> {
    
    	private String index;
    
    	public CallableTest() {
    		super();
    	}
    
    	public CallableTest(String index) {
    		super();
    		this.index = index;
    	}
    
    	@Override
    	public String call() throws Exception {
    		System.out.println(Thread.currentThread().getName() + " --- " + index
    				+ "开始执行,循环输出5次index");
    		for (int i = 0; i < 5; i++) {
    			System.out.println(index + " -- 第" + i + "次执行");
    		}
    		System.out.println(Thread.currentThread().getName() + "执行完毕");
    		Thread.sleep(5000);
    		System.out.println(index + " - 等待5秒再返回结果");
    		return index + "执行成功!";
    	}
    
    	public String getIndex() {
    		return index;
    	}
    
    	public void setIndex(String index) {
    		this.index = index;
    	}
    
    }
    

      运行

    public static void testCallable() {
    		CallableTest thread1 = new CallableTest();
    		thread1.setIndex("A");
    		FutureTask<String> ft = new FutureTask<String>(thread1);
    		new Thread(ft).start();
    		try {
    			/**
    			 * ft.get() 执行这条时,如果一直没有结果,会一直等待结果返回再继续执行下面的
    			 */
    			System.out.println(System.currentTimeMillis());
    			System.out.println("线程执行结果:" + ft.get());
    			System.out.println(System.currentTimeMillis());
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    

      结果

    4、使用线程池

    定义一个线程池

    package com.jc.thread.impl;
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ThreadFactory;
    import java.util.concurrent.atomic.AtomicInteger;
    
    public class ExecutorUtil {
    	
    public static ExecutorService fixedThreadPool = null;
        
        static{
            int cpuNums = Runtime.getRuntime().availableProcessors();
            fixedThreadPool = Executors.newFixedThreadPool(cpuNums * 2,new ThreadFactory(){
            	//给这个线程池里的预备线程起个名
                private final AtomicInteger mCount = new AtomicInteger(1);
                @Override
                public Thread newThread(Runnable r){
                    return new Thread(r,"jc-thread-" + mCount.getAndIncrement());
                }
            });
        }
    
    }
    

      

     

    Runnable  方式使用

    public static void testExecRun() {
    		ExecutorService executor = ExecutorUtil.fixedThreadPool;
    		RunableTest thread1 = new RunableTest();
    		thread1.setIndex("A");
    		RunableTest thread2 = new RunableTest("B");
    		executor.execute(thread1);
    		executor.execute(thread2);
    
    		executor.shutdown();
    	}
    

      

    Callable 方式使用

    public static void testExecCall() {
    		ExecutorService executor = ExecutorUtil.fixedThreadPool;
    		List<Future<String>> results = new ArrayList<Future<String>>();
    		CallableTest thread1 = new CallableTest();
    		thread1.setIndex("A");
    		CallableTest thread2 = new CallableTest("B");
    		results.add(executor.submit(thread1));
    		results.add(executor.submit(thread2));
    
    		for (Future<String> future : results) {
    			try {
    				/**
    				 * future.get() 执行这条时,如果一直没有结果,会一直等待结果返回再继续执行下面的
    				 */
    				System.out.println("线程执行结果:" + future.get());
    			} catch (Exception e) {
    				e.printStackTrace();
    			}
    		}
    		executor.shutdown();
    	}
    

      结果

    参考文章:

    https://www.jianshu.com/p/210eab345423

    https://blog.csdn.net/evankaka/article/details/44153709

    https://www.cnblogs.com/echo-cheng/p/6814909.html

    https://blog.csdn.net/weixin_42606135/article/details/81282736

    https://blog.csdn.net/u012660667/article/details/49102107

    -------------------------------------------------------------------------------------------------------------------------------------------------------------- 白云苍狗时光飞,嘻嘻哈哈一生追。哈!
  • 相关阅读:
    MySQL中内存分为全局内存和线程内存
    mysql 线程级别的缓冲区
    MySQL Handler变量解析
    HANDLER命令与实现
    MySQL Spatial Extensions 地理信息
    C++中临时对象的学习笔记
    HDC与CDC相互转换
    B树
    基于R-Tree的最近邻查询
    地图发布的几种服务的区别
  • 原文地址:https://www.cnblogs.com/sangong/p/11967912.html
Copyright © 2011-2022 走看看