zoukankan      html  css  js  c++  java
  • JAVA基础 (五) 多线程

             首先从宏观上来看一下java中多线程内容:


           本篇博客主要介绍三种启动多线程的方式,以及对比哪种方式比较好。

    1.继承Thread类

           下面代码中成员变量为i,分为启用两个线程,经测试每个线程自己独占一个成员变量,即多个线程之间并不能够共享成员变量。

    <span style="font-size:14px;">package com.test.process;
    
    public class ExtendsThread extends Thread{
    
    	private int i;
    	//重写run()方法,run()方法的方法体就是线程执行体
    	public void run()
    	{
    		for(int i=0;i<100;i++)
    		{
    			//当线程类继承Thread类时,直接使用this即可获取当前线程
    			//Thread对象的getName()返回当前线程名字
    			//因此可以直接调用getName()方法返回当前线程的名字
    			System.out.println(getName()+"   "+i);
    			
    		}
    	}
    	
    	public static void main(String[] args) {
    		for(int i=0;i<100;i++)
    		{
    			//调用Thread类的currentThread()方法获取当前线程
    			System.out.println(Thread.currentThread().getName()+"  "+i);
    			if(i==20)
    			{
    				//创建并启动一个线程
    				new ExtendsThread().start();
    				//创建并启动第二个线程
    				new ExtendsThread().start();
    			}
    		}
    	}
    }
    </span>

    2.实现Runnable接口

           该方式经测试两个线程共享一个成员变量,这种方式把该类作为了目标对象放到了线程中,即两个线程用的是同一个实例,因此他们成员变量是一样的,操作的一个成员变量。

    <span style="font-size:14px;">package com.test.process;
    
    public class ImplementRunnable implements Runnable{
    
    	private int i;
    	//重写run()方法,run()方法的方法体就是线程执行体
    	public void run()
    	{
    		for( ;i<100;i++)
    		{
    			//当线程类实现Runnable接口时
    			//如果想获得当前线程,只能使用Thread.currentThread()方法
    			System.out.println(Thread.currentThread().getName()+"   "+i);
    			
    		}
    	}
    	
    	public static void main(String[] args) {
    		for(int i=0;i<100;i++)
    		{
    			//调用Thread类的currentThread()方法获取当前线程
    			System.out.println(Thread.currentThread().getName()+"  "+i);
    			if(i==20)
    			{
    				ImplementRunnable implRun=new ImplementRunnable();
    				//创建并启动一个线程
    				new Thread(implRun,"新线程1").start();
    				//创建并启动第二个线程
    				new Thread(implRun,"新线程2").start();
    				new Thread(implRun,"新线程3").start();
    				new Thread(implRun,"新线程4").start();
    				System.out.println("123");
    				
    			}
    		}
    	}
    }
    </span>

    3.实现Callable接口和Future接口

           Callable对runnable接口进一步封装了一下,该类可以有返回值还可以声明异常类。

    <span style="font-size:14px;">package com.test.process;
    
    import java.util.concurrent.Callable;
    import java.util.concurrent.FutureTask;
    
    public class CallableFuture implements Callable<Integer>{
    
    	//实现call()方法作为线程执行体
    	public Integer call()
    	{
    		 int i=0;
    		//重写run()方法,run()方法的方法体就是线程执行体
    		for( ;i<100;i++)
    		{
    			//当线程类实现Runnable接口时
    			//如果想获得当前线程,只能使用Thread.currentThread()方法
    			System.out.println(Thread.currentThread().getName()+"   "+i);
    		}
    		return i;
    	}
    	
    	public static void main(String[] args) {
    	
    		//创建callable对象
    		CallableFuture callablefuture=new CallableFuture();
    		//使用FutureTask来包装callable对象
    		FutureTask<Integer> futuretask=new FutureTask<Integer>(callablefuture);
    		
    		for(int i=0;i<100;i++)
    		{
    			//调用Thread类的currentThread()方法获取当前线程
    			System.out.println(Thread.currentThread().getName()+"  "+i);
    			if(i==20)
    			{
    				//创建并启动一个线程
    				new Thread(futuretask,"有返回值的线程").start();
    			}
    		}
    		
    		try {
    			//获取线程返回值
    			System.out.println("线程返回值为="+futuretask.get());
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		
    	}
    }
    </span>

    三种方式对比:

           通过继承Thread类或者实现Runnable、Callable接口都可以实现多线程,不过实现Runnable与实现Callable接口的方式基本相同,只是Callable接口里定义的方法有返回值,可以声明异常。

           采用接口方式创建线程

           1.线程类只是实现了Runnable接口或Callable接口,还可以继承其他类。

           2.多个线程可以共享同一个target对象,非常适合多个相同线程来处理同一份资源。

           3.不过编程少复杂

          采用继承方式

          1.编程简单

          2.继承了Thread类,不能再继承其他父类

    在项目中如果涉及到多线程编程,建议使用中接口的方式,这种方式可以有返回值也可以共享成员变量,给编程带来便利。

           由此,让我想到了struts1、struts2中action的创建,struts1中action是单例的所有的请求都共用一个action实例,它们都访问其成员变量故存在线程安全问题,而struts2常与spring集成,他们集成之后action交给spring管理,spring通过配置文件将bean标签的scope属性设为prototype,表示每个有请求时都为它实例化一个action,这样将会是线程安全的。

          


  • 相关阅读:
    解决jenkins sonar扫描中文名的文件会失败
    ukey命令行签名:解决safenet ukey 每次签名都要输入token password问题(批量签名)
    vmp如何使用命令行加壳exe或者dll
    tomcat 安装的jenkins的迁移解决磁盘爆满的问题
    cocoapods 执行pod trunk push 报错CDN: trunk URL couldn't be downloaded: https://raw.githubusercontent.com/CocoaPods/Specs/master/Spec
    使用NodeJs搭建的小型web应用
    对WebSocket技术的学习与探索(一)
    Git本地操作相关介绍
    NodeJs入门学习(一)
    ES6深入学习记录(三)编程风格
  • 原文地址:https://www.cnblogs.com/lilongsheng1125/p/4978497.html
Copyright © 2011-2022 走看看