文档章节

Java多线程

素人派
 素人派
发布于 2016/12/31 20:44
字数 1008
阅读 4
收藏 0
  • 介绍
在使用Java作为开发语言时,如果需要高效率、并行地处理请求,通常采用的方法就是“多线程”。 我们可以简单地认为多个线程是同时在运行的,这样效率自然就会很高,那是不是同时开启的线程越多,效率越高呢。不是这样的,因为所有这些线程都是需要一个调度中心来保证协调地工作的,就好比有时候“人多反而误事”。所以说,是不是要采用多线程,以及要同时开启多少个线程都是要根据实际需要来定的,不是越多越好。 那多少个线程数才是合适的呢,最笨也最好的办法就是通过测试结果来定。但是,由于多个线程是要争夺CPU资源来实现并行的,这样我建议可以使用CPU数量的两倍来定。
  • 最简单的线程使用
在Java中要实现一个线程,可以通过继承java.lang.Thread类或者是实现java.lang.Runnable接口。其中的run方法就是线程的实现逻辑,调用start方法来启动线程。 下面的例子是继承了Thread类: [codesyntax lang="java"]
/**
 * @author suren
 * @date 2015-4-1
 *
 * http://surenpi.com
 */
public class Test
{

	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception
	{
		SuRenThread threadA = new SuRenThread();
		SuRenThread threadB = new SuRenThread();

		threadA.start();
		threadB.start();
	}

}

class SuRenThread extends Thread
{

	@Override
	public void run()
	{
		System.out.println(System.currentTimeMillis());
	}
}
[/codesyntax] 下面的例子是实现了Runnable接口: [codesyntax lang="java"]
/**
 * @author suren
 * @date 2015-4-1
 *
 * http://surenpi.com
 */
public class Test
{

	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception
	{
		Thread threadA = new Thread(new SuRenRunnable());
		Thread threadB = new Thread(new SuRenRunnable());

		threadA.start();
		threadB.start();
	}

}

class SuRenRunnable implements Runnable
{

	@Override
	public void run()
	{
		System.out.println(System.currentTimeMillis());
	}
}
[/codesyntax] 上述两种实现线程的方式都可以使用,但是由于Java规定类只能单继承,所以要使用继承Thread类的方式的话,就无法继承别的类了,这是他们的一个区别。
  • 线程同步
基本上只要使用了多线程,就会不可避免地要处理线程之间读写公共数据的安全性问题。使用线程间同步的方法是解决安全问题的一个手段。 使用关键字synchronized来实现同步,它可以加在方法或者代码块上。下面给出一个例子: [codesyntax lang="java"]
package struts2.hibernate.spring;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolTest {

	public static void main(String[] args) {
		ExecutorService service = Executors.newCachedThreadPool();
		
		StringBuffer bufA = new StringBuffer("abc");
		StringBuffer bufB = new StringBuffer("def");
		StringBuffer bufC = new StringBuffer("gbi");
		
		for(int i = 0; i < 8; i++) {
			service.execute(new SuRenRun(bufA, bufB, bufC));
		}
	}
}

class SuRenRun implements Runnable {
	
	private StringBuffer bufA;
	private StringBuffer bufB;
	private StringBuffer bufC;
	
	public SuRenRun(StringBuffer bufA, StringBuffer bufB, StringBuffer bufC) {
		this.bufA = bufA;
		this.bufB = bufB;
		this.bufC = bufC;
	}

	public void run() {
		visit();
	}
	
	synchronized void visit() { //加在了当前实例对象上
		System.out.println(bufA.append(bufA.length()));
		
		hello();
	}
	
	void hello() {
		synchronized(bufB) { //加在实例对象上
			System.out.println("=======" + bufB.append(bufB.length()));
		}
		
		synchronized(String.class) { //加在类对象上
			System.out.println("----" + bufC.append(bufC.length()));
		}
	}
}
[/codesyntax] synchronized的实现原理是从软件层面依赖JVM。
  • 线程锁
这里说的线程锁指的是接口java.util.concurrent.locks.Lock,它的实现原理是从硬件层面依赖特殊的CPU指令。ReentrantLock是Lock接口的一个实现类。 另外,还有一个读写锁的接口java.util.concurrent.locks.ReadWriteLock。
  • 线程池
java.util.concurrent.ExecutorService是JRE中提供的用于实现线程池的一个比较重要的接口。 下面是一个最简单的线程池的例子: [codesyntax lang="java"]
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author suren
 * @date 2015-4-1
 *
 * http://surenpi.com
 */
public class Test
{

	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception
	{
		ExecutorService service = Executors.newCachedThreadPool();

		service.execute(new SuRenRunnable());
		service.execute(new SuRenRunnable());
		service.execute(new SuRenRunnable());
	}

}

class SuRenRunnable implements Runnable
{

	@Override
	public void run()
	{
		System.out.println(System.currentTimeMillis());
	}
}
[/codesyntax] Executors.newCachedThreadPool()这种线程池维护0个核心线程数,最大线程数量为Integer.MAX_VALUE,线程的空闲失效时间为60秒。由此特性,可以想象到这种线程池适合于大量执行时间很短的任务。 Executors.newFixedThreadPool(int nThreads) Executors.newSingleThreadExecutor() Executors.newScheduledThreadPool(int corePoolSize) 除了JDK提供的线程池的实现以外,Spring也提供了相应的实现,详细内容请查阅《 Spring线程池》。 对于JDK中提供的集合相关的线程安全性问题,请查阅《Java集合中的线程安全问题》。

本文转载自:http://surenpi.com/2015/05/08/java_multi_thread/

共有 人打赏支持
素人派
粉丝 25
博文 1907
码字总数 10223
作品 6
东城
程序员
私信 提问

暂无文章

想问一下C++里queue要怎么遍历

如题,想知道怎么遍历<queue>对象的元素? 貌似不能遍历。要么全部pop push一遍,要么换个容器呗。 queue是先进后出的数据类型,只能不断读top()然后再pop()掉。故意把遍历操作隐藏掉了,...

shzwork
昨天
2
0
Ubuntu 18.04.2 LTS nvidia-docker2 : 依赖: docker-ce (= 5:18.09.0~3-0~ubuntu-bionic)

平台:Ubuntu 18.04.2 LTS nvidia-docker2 版本:2.0.3 错误描述:在安装nvidia-docker2的时候报dpkg依赖错误 nvidia-docker2 : 依赖: docker-ce (= 5:18.09.0~3-0~ubuntu-bionic) 先看一下依......

Pulsar-V
昨天
3
0
学习笔记1-goland结构体(struct)

写在前面:若有侵权,请发邮件by.su@qq.com告知。 转载者告知:如果本文被转载,但凡涉及到侵权相关事宜,转载者需负责。请知悉! 本文永久更新地址:https://my.oschina.net/bysu/blog/3036...

不最醉不龟归
昨天
4
0
【转】go get命令使用socket代理

由于某些不可描述的原因,国内使用go get命令安装某些包的时候会超时导致失败,比如net包、sys包、tools包等。第一种解决办法就是自己从git上下载后添加链接到GOPATH中,比如: 1234...

yiduwangkai
昨天
6
0
从上往下打印出二叉树的每个节点,同层节点从左至右打印。

//第一种做法 public class Solution { public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) { ArrayList <Integer> li=new ArrayList<Integer>(); ArrayList <TreeN......

南桥北木
昨天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部