1、继承Thread类创建线程类
public class FirstThreadTest extends Thread {
public void run(){
System.out.println("这里是线程的执行方法");
}
public static void main(String[] args) {
//获得线程
FirstThreadTest thread = new FirstThreadTest();
System.out.println("线程名称为:"+thread.getName());
//启动线程
thread.start();
System.out.println("main方法也是一个线程:"+Thread.currentThread().getName());
}
}
执行结果:
线程名称为:Thread-0
main方法也是一个线程:main
这里是线程的执行方法
2、通过Runnable接口创建线程类
(1)定义runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体;
(2)创建 Runnable实现类的实例,并依此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象;
(3)调用线程对象的start()方法来启动该线程。
public class RunnableThreadTest implements Runnable {
public void run() {
System.out.println("这里是线程方法");
System.out.println("线程名为:" + Thread.currentThread().getName());
}
public static void main(String[] args) {
System.out.println("main方法线程:" + Thread.currentThread().getName());
RunnableThreadTest rtt = new RunnableThreadTest();
new Thread(rtt, "新线程1").start();
new Thread(rtt, "新线程2").start();
}
}
执行结果
main方法线程:main
这里是线程方法
线程名为:新线程1
这里是线程方法
线程名为:新线程2
两种线程创建的具体区别:http://www.cnblogs.com/whgw/archive/2011/10/03/2198506.html(扩展性和资源共享性)
多线程并发
多线程并发出现问题主要涉及到两个方面:多线程共享数据同步问题和数据因并发产生不一致问题;
1、多线程共享数据同步问题
如下代码:
/**
* 两个工人一起搬砖
*/
public class Banzhuan {
public static void main(String[] args) {
// 一个工厂
Factory factory = new Factory();
/**
* p1线程和p2线程都是由factory这个实例创建的
* 那么p1调用外部类的getZhuanTou()方法就相当于调用的是factory这个实例的getZhuanTou(),同样的,p2调用的也是factory这个实例的getZhuanTou().
* 那么这里就出现了两个线程同时访问factory的getZhuanTou()方法。
* 而factory的getZhuanTou()方法又对zhuanTou这个属性进行了zhuanTou--操作。
* 换句话说,两个线程同时访问了factory的数据zhuanTou.这时候就可能产生线程安全问题。
*/
// 同一个工厂的两个工人
Person p1 = factory.getPerson();
Person p2 = factory.getPerson();
p1.start();
p2.start();
}
}
// 工厂
class Factory {
int zhuanTou = 20;// 一共20块砖头
public int getZhuanTou() {
if (zhuanTou == 0) {
throw new RuntimeException(Thread.currentThread().getName()+ ",没有砖头搬了!");
}
Thread.yield();
return zhuanTou--;
}
// 工人
class Person extends Thread {
// 不停的搬砖
public void run() {
while (true) {
// 获取线程名(工人名) 及 剩下砖头数
System.out.println(getName() + "搬了第" + getZhuanTou() + "块砖头");
// 当线程的run方法中出现了异常,且我们没有 解决,那么该线程终止并死亡。但不会影响 当前进程中的其他线程。
Thread.yield();
}
}
}
// 获取工人
public Person getPerson() {
return new Person();
}
}
多次运行结果:
这里并不是每次都会出错,要多运行几次,就会可能碰到多种错误,比如搬到了同一块砖,比如少搬一块砖,比如搬完到了0然后还有继续搬……
原因是:比如现在还剩15块砖头,工人p1搬第15块砖头的时候正拿到手上,但是还没有登记减少一块砖头(即还没有运行zhuanTou–),这个时候工人p2也去拿砖,然后登记的时候一看还剩15块砖头,实际呢只剩14块了……
解决方法:
synchronized:当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。
所以将getZhuanTou()方法改成如下就可以了
public int getZhuanTou() {
synchronized (this) {
if (zhuanTou == 0) {
throw new RuntimeException(Thread.currentThread().getName()+",没有砖头搬了!");
}
Thread.yield();
return zhuanTou--;
}
}
为啥不将这个关键词锁在方法那呢?尽量将锁在范围最小的地方,这样运行的效率更快。
2、数据因并发产生不一致问题
参考:https://my.oschina.net/clopopo/blog/149368
ThreadLocal:为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象。
首先,ThreadLocal 不是用来解决共享对象的多线程访问问题的,一般情况下,通过ThreadLocal.set() 到线程中的对象是该线程自己使用的对象,其他线程是不需要访问的,也访问不到的。各个线程中访问的是不同的对象;
另外,说ThreadLocal使得各线程能够保持各自独立的一个对象,并不是通过ThreadLocal.set()来实现的,而是通过每个线程中的new 对象的操作来创建的对象,每个线程创建一个,不是什么对象的拷贝或副本。
再次,注意每一个线程都保存一个对象的时候(非基本类型数据)应该是new一个新对象而不是引用一个对象,如下:
private static ThreadLocal<Index> local = new ThreadLocal<Index>() {
@Override
protected Index initialValue() {
return new Index(); //注意这里
}
};
案例代码:
public class ThreadLocalTest {
//创建一个Integer型的线程本地变量
public static final ThreadLocal<Integer> local = new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return 0;
}
};
public static void main(String[] args) throws InterruptedException {
Thread[] threads = new Thread[5];
for (int j = 0; j < 5; j++) {
threads[j] = new Thread(new Runnable() {
@Override
public void run() {
//获取当前线程的本地变量,然后累加5次
int num = local.get();
for (int i = 0; i < 5; i++) {
num++;
}
//重新设置累加后的本地变量
local.set(num);
System.out.println(Thread.currentThread().getName() + " : "+ local.get());
}
}, "Thread-" + j);
}
for (Thread thread : threads) {
thread.start();
}
}
}
运行结果:
Thread-0 : 5
Thread-4 : 5
Thread-2 : 5
Thread-1 : 5
Thread-3 : 5
--------------------------------------------------------------------------------------------------
3、总结:
ThreadLocal和Synchonized都用于解决多线程并发访问。但是ThreadLocal与synchronized有本质的区别:
1、synchronized关键字主要解决多线程共享数据同步问题,ThreadLocal使用场合主要解决多线程中数据因并发产生不一致问题;
2、synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通信时能够获得数据共享;
synchronized和ThreadLocal比较:http://blog.csdn.net/huyongl1989/article/details/8088841
线程池
当有许多请求需要去处理的时候,如果只是单独的一个人去处理,可想而知那会让后面在排队的人等多久,这样就需要线程池,有请求过来了就到线程池里面取出一条线程去处理它,处理完成就把它收回到线程池里面,然而自己实现 一个功能强大的线程池也并非易事,在java1.5之后专门提供了线程池的类库。
Java通过Executors接口提供四种线程池,分别为:
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程;
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待;
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行;
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行;
下面简单看一下newFixedThreadPool这种线程池:
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
final int index = i;
fixedThreadPool.submit(new Runnable() {
public void run() {
try {
System.out.println(Thread.currentThread().getName()+"---->"+index);
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
}
运行:
pool-1-thread-1—->0
pool-1-thread-3—->2
pool-1-thread-2—->1
pool-1-thread-3—->3
pool-1-thread-2—->5
pool-1-thread-1—->4
pool-1-thread-3—->6
pool-1-thread-1—->8
pool-1-thread-2—->7
pool-1-thread-3—->9
因为线程池大小为3,每个任务输出index后sleep 2秒,所以每两秒打印3个数字。
fixedThreadPool.submit(Runnable task)或者execute方法会调用线程的run方法;
线程池参考地址:http://blog.csdn.net/u012385190/article/details/52486393
相关推荐
java多线程并发查询数据库,使用线程池控制分页,并发查询。
里面是自己收藏的几篇关于线程的文档资料,大家可以看看哈
Java多线程实现数据切割批量执行,实现限流操作。 java线程池Executors实现数据批量操作。 批量异步Executors处理数据,实现限流操作,QPS限流。 线程池调用第三方接口限流实现逻辑。 案例适合: 1.批量处理大数据。...
volatile关键字的非原子性、volatile关键字的使用、AtomicInteger原子性操作、线程安全小例子:多个线程竞争问题、多个线程多个锁问题、创建一个缓存的线程池、多线程使用Vector或者HashTable的示例(简单线程同步...
不了解并发编程和线程池的开发者可能会面临多线程竞争、死锁等问题。通过深入了解 Java 并发编程和 JUC 线程池,您可以更好地管理线程之间的协作和同步,充分发挥多核处理器的优势,确保程序稳定运行。 了解 Java ...
Java多线程和线程池是Java语言中非常重要的知识点,它们可以帮助我们更好地管理和控制程序的并发执行。本资源主要是对Java多线程和线程池进行详细的讲解和练习。
线程池的多线程并发控制技术研究.caj 线程池的多线程并发控制技术研究.caj 线程池的多线程并发控制技术研究.caj
Java线程:新特征-线程池 Java线程:新特征-有返回值的线程 Java线程:新特征-锁(上) Java线程:新特征-锁(下) Java线程:新特征-信号量 Java线程:新特征-阻塞队列 Java线程:新特征-阻塞栈 Java线程:...
详细的讲述了多线程的各种用法 Java线程:概念与原理 Java线程:创建与启动 Java线程:线程栈模型与线程的变量 Java线程:线程状态的转换 Java线程:线程的同步与锁 Java线程:线程的交互 Java线程:线程的调度-休眠...
Java多线程读取大文本文件并批量插入MongoDB的代码,文本文件,csv文件,可以结合POI改造使其支持excel。 适合做大量文本数据或日志文件入库的场景,大文本被拆分成多个线程处理,速度快。 批量插入MongoDB,存在则...
01、【中级原理】java多线程并发编程入门原理精通视频教程 02、【中级原理专题】java并发编程多线程高级专题课程 03. 【中级原理】高并发编程原理和线程池精通教程 04、【高级原理】Java并发多线程编程基础原理与...
刚学完多线程和线程池,以及线程爱好者。 使用场景及目标: 大文件的快速下载,经测试在100M带宽的网络下,下载一个40M的文件,不超过两秒钟,当然还得根据自己电脑的配置来讲。 其他说明: 文件如果特别小,而...
这个是关于Java多线程方面的技术,就是多个线程发送请求,从互联网上下载图片资源,通过这个案例可以知道Java中的多线程的基础知识
在多线程大师Doug Lea的贡献下,在JDK1.5中加入了许多对并发特性的支持,例如:线程池。.......................................JAVA线程、线程池资料----下载不扣分,回帖加1分,欢迎下载,童叟无欺JAVA线程、...
Java多线程(Synchronized+Volatile+JUC 并发工具原理+线程状态+CAS+线程池)
java多线程设计模式,附源码中文教程,java并发核心编程,JAVA线程池原理以及几种线程池类型介绍
主要介绍了使用java的HttpClient实现多线程并发的相关资料,需要的朋友可以参考下
本书全面解析了Java并发编程的核心概念、原理和实践,帮助读者深入理解多线程并发编程的精髓,提升编程能力和系统性能。 书中首先介绍了并发编程的基础知识,包括线程的基本概念、线程的生命周期、线程安全等问题。...