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编程中至关重要的概念,特别是在处理高并发、高性能的系统设计时。以下是对这些主题的详细说明: 1. **Java 程序中的多线程** - 多线程允许一个程序同时执行多个任务,提高程序...
Java 模拟线程并发是编程领域中的一个重要概念,尤其在多核处理器和高并发应用中,理解并熟练掌握线程并发技术对于提升程序性能至关重要。在Java中,线程并发可以通过多种方式实现,包括继承Thread类、实现Runnable...
综上所述,"java多线程查询数据库"是一个涉及多线程技术、线程池管理、并发控制、分页查询等多个方面的复杂问题。通过理解和掌握这些知识点,我们可以有效地提高数据库操作的效率和系统的响应速度。
### Java多线程并发知识点详解 #### 一、Java多线程并发简介 在现代软件开发中,特别是在Java这样的主流编程语言中,多线程并发技术是提高程序执行效率、优化资源利用的关键手段之一。本篇文章将深入探讨Java中的...
但同时,多线程并发也会引入一些问题,如数据竞争和同步问题。 为了解决这些问题,Java提供了多种同步机制。`synchronized`关键字用于控制对共享资源的访问,确保同一时间只有一个线程可以执行特定代码块,从而避免...
在Java编程语言中,线程并发和线程池是多任务执行的核心概念,尤其是在JDK 1.5及以后的版本中得到了显著增强。线程并发允许程序同时执行多个任务,提高了程序的效率和响应性。线程池是管理线程资源的有效方式,通过...
Java中的线程池是多线程编程中一种高效、可管理的执行机制。它通过预先创建并维护一组线程,避免了频繁地创建和销毁线程带来的开销,从而提高了程序的性能和响应速度。线程池的核心概念包括以下几个方面: 1. **...
Java多线程并发实战与源码分析是Java开发中至关重要的一部分,它涉及到程序性能优化、系统资源高效利用以及复杂逻辑的正确同步。本书主要聚焦于Java多线程的基础理论和实际应用,虽然书中实例和源码相对较少,但仍然...
本文将深入探讨如何在Winform应用中使用异步多线程和线程池。 一、线程基础 线程是操作系统分配CPU时间的基本单元,每个进程至少包含一个线程。在C#中,可以使用`System.Threading.Thread`类来创建和管理线程。通过...
#### 二、Java多线程分页查询原理及实现 ##### 1. 分页查询基础概念 分页查询是指在查询数据时,将数据分成多个页面展示,而不是一次性返回所有数据。这种方式能够有效地减少单次查询的数据量,从而提高查询速度和...
Java多线程与并发编程是Java语言中用于处理多任务执行的关键技术,它能够帮助开发者设计出能够有效应对高并发请求的应用程序。在现代的线上(Online)和离线(Offline)应用中,合理利用多线程技术可以大幅提高系统...
在多线程环境下,可以实现并行和并发执行。并行是指多个独立的任务同时运行,而并发则是在同一时间段内交替执行多个任务,通常在单个CPU核心上实现。在具有共享资源的并发场景中,线程安全和同步变得至关重要,以...
Java多线程实现数据切割批量执行,实现限流操作。 java线程池Executors实现数据批量操作。 批量异步Executors处理数据,实现限流操作,QPS限流。 线程池调用第三方接口限流实现逻辑。 案例适合: 1.批量处理大数据。...
本文将围绕“Java多线程高并发相关资料收集”这一主题,详细探讨这两个领域的核心知识点。 首先,多线程是指在单个程序中同时执行多个线程。Java提供了一个强大的多线程支持,允许开发者创建、管理和控制多个执行...
通过以上方法,我们可以在Java中有效地利用多线程处理数据库数据,提高程序的并发能力和效率。记得在设计时充分考虑线程间的协作与同步,以及数据库连接的管理和优化,以确保程序的稳定性和性能。
volatile关键字的非原子性、volatile关键字的使用、AtomicInteger原子性操作、线程安全小例子:多个线程竞争问题、多个线程多个锁问题、创建一个缓存的线程池、多线程使用Vector或者HashTable的示例(简单线程同步...
线程池是一种多线程处理形式,预先创建了若干个线程,当有任务需要执行时,会从线程池中取出一个线程来执行任务,任务执行完毕后,线程返回线程池中等待新的任务。这种机制避免了频繁创建和销毁线程带来的性能开销,...
在IT领域,多线程控制、线程池模式和HTTP线程是三个关键概念,尤其在高并发和高性能系统设计中扮演着重要角色。本文将深入探讨这些知识点,并结合实际应用进行阐述。 首先,让我们从多线程控制开始。多线程是指在一...
总之,"轻量级java多线程池demo"通过结合Java多线程和Actor模型,提供了一种高效、可扩展的并发解决方案。通过学习和实践这样的示例,开发者可以更好地理解和掌握Java并发编程的技巧,提升软件的性能和可维护性。...
Java8并行流中自定义线程池操作示例主要介绍了Java8并行流中自定义线程池操作,结合实例形式分析了并行流的相关概念、定义及自定义线程池的相关操作技巧。 1. 概览 Java8引入了流的概念,流是作为一种对数据执行...