java线程基础
Posted _oldzhang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java线程基础相关的知识,希望对你有一定的参考价值。
1,创建线程的两种方式:
A, 继承Thread类,重写run方法,通过查看Thread源代码可看出run方法只会调用存在的runnable成员变量的target的run方法。
B, 实现runnable接口并传递给Thread类作为成员变量。
package com.thread;
class Thread1 extends Thread
@Override
public void run()
System.out.println(this.getName());
super.run();
public class ThreadTest1
public static void main(String[] args)
Thread t = new Thread(new Runnable()
@Override
public void run()
System.out.println(Thread.currentThread().getName());
);
t.start();
Thread1 t1 = new Thread1();
t1.start();
线程终止的方式:
使用线程的interrupt()方法进行中断,stop()方法进行停止,使用标识位进行取消。
建议使用标识位方法,这种方式使线程在终止时有机会清理资源。
Suspend() resume() stop()方法都不建议使用,以suspend()为例,调用后线程不释放资源,比如锁,容易造成死锁,stop也一样。
2,传统计时器:
new Timer().schedule
Timer作为调度器,调用schedule方法执行调度,真正的执行逻辑在TimerTask的实现类中。
3,线程互斥:
同一段逻辑不能同时被多个线程同时执行为线程互斥
volatile和synchronized关键字:
java支持多线程同时访问一个对象或者对象的成员变量,且每个线程可以拥有这个变量的拷贝(虽然对象和成员变量是分配在内存中的共享内存中,但执行的线程还是可以拥有一份拷贝,目的是加速程序的执行)
volatile就是用来修饰成员变量的,保证读取从共享内存读,写入必须刷新到共享内存,保证了成员变量的内存可见性。
Synchronized修饰方法或代码块,保证了线程对变量访问的可见性与排他性。
4,线程同步通信:
Wait方法使当前运行的线程等待并释放锁/Notify唤醒其它线程
互斥是指线程不可同时运行,同步通信是指一个线程与其它线程进行协作。
等待/通知机制:一个线程A调用了对象O的wait()方法进入等待状态,另一个线程B调用了对象O的notify()方法,线程A收到通知后从对象O的wait()方法返回,继续执行。
A,使用wait(),notify()需要先对调用对象加锁。
B,notify()调用之后,等待线程不会从wait()返回,需要调用notify()的线程释放锁才有机会从wait()中返回
C,等待/通知机制依托于同步机制,其目的就是确保等待线程从wait()方法返回时能够感知到通知线程对变量做出的修改。
例子:要求子线程与主线程交替运行,子线程打印10个数,主线程打印20个数,交替运行50次。
分析:
A,打印10个数与打印20个数的方法应该互斥,所以这两个方法都需要加synchronized。保证在子线程打印10个数期间,主线程不能开始打印20个数。
B,子线程打印完后应通知主线程进行打印,需要线程间的通信。需要使用wait与notify
C,设置一个变量来控制此时该哪个线程运行。两个方法为同步关系,应该放在同一类中进行设计。
package com.thread;
class Business
private boolean shouldsub = true;
public synchronized void sub(int i)
if(!shouldsub)
try
this.wait();
catch (InterruptedException e)
e.printStackTrace();
for(int j = 1; j<=10; j++)
System.out.println("sub "+j +" in "+i);
shouldsub = false;
this.notify();
public synchronized void main(int i)
if(shouldsub)
try
this.wait();
catch (InterruptedException e)
e.printStackTrace();
for(int j = 1; j<=20; j++)
System.out.println("main "+j +" in "+i);
shouldsub = true;
this.notify();
public class TraditionalThreadcommunication
public static void main(String[] args)
final Business business = new Business();
new Thread(new Runnable()
@Override
public void run()
for(int i = 1; i<=50; i++)
business.sub(i);
).start();
for(int i = 1; i<=50; i++)
business.main(i);
等待/通知的经典范式:
等待方遵循如下原则:
1, 获取对象的锁
2, 如果条件不满足,则调用对象的wait方法,被通知后仍要检查条件
3, 条件满足则执行对应的逻辑
伪代码如下:
Synchronized(对象)
While(条件不满足)
对象.wait();
对应的处理逻辑
通知方遵循如下原则:
1, 获得对象的锁
2, 改变条件
3, 通知所有等待在对象上的线程
对应伪代码如下:
Synchronized(对象)
改变条件
对象.notifyAll();
package com.thread;
/**
* 将共享数据封装在另外一个对象中 然后在Runnable实现类中使用这个对象
* 每个线程对共享数据的操作方法也分配到这个对象上中 容易实现互斥与通信
*
* 也可以不通过匿名内部类实现 显式声明两个线程实现Runnable
* 将data1分别作为构造函数参数传入给其中使用也可以
* @author zhangyaping050
*/
public class MultiThreadShareData
public static void main(String[] args)
final ShareData1 data1 = new ShareData1();
new Thread(new Runnable()
@Override
public void run()
data1.incre();
).start();
new Thread(new Runnable()
@Override
public void run()
data1.decr();
).start();
class ShareData1
private int j = 0;
public synchronized void incre()
j++;
public synchronized void decr()
j--;
5,线程池:
创建固定数目线程池:ExecutorService threadPool = Executors.newFixedThreadPool(3);
创建缓冲线程池:ExecutorService threadPool2 = Executors.newCachedThreadPool();
创建单个线程的线程池:ExecutorService threadPool3 = Executors.newSingleThreadExecutor();
threadPool.execute(new Runnable()
@Override
publicvoid run()
for(intj=1; j<10; j++)
System.out.println(Thread.currentThread().getName()+": "+j+" in "+task);
);
往线程池添加执行任务。
调用threadPool.shutdown();线程池执行完任务后会关闭
package com.thread.lock;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* 简单缓存系统设计
* 同一个读写锁对象的多个读锁之间不互斥 读锁与写锁之间互斥 写锁与写锁之间互斥
* @author zhangyaping050
*/
public class CacheDemo
private Map<String, Object> cache = new HashMap<String, Object>();
private ReadWriteLock rwl = new ReentrantReadWriteLock();
public static void main(String[] args)
public Object getData(String key)
rwl.readLock().lock();
Object value = null;
try
value = cache.get(key);
if (value == null)
rwl.readLock().unlock();
rwl.writeLock().lock();
try
if (value == null)
value = "aa"; // query db
finally
rwl.writeLock().unlock();
rwl.readLock().lock();
finally
rwl.readLock().unlock();
return value;
Condition:
Condition的功能类似传统的wait()和notify()方法的功能
一个锁内部可以有多个Condition,即有多路等待和通知,比wait和notify方法更强大
下面是利用Condition实现阻塞队列
package com.thread.lock;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Condition的功能类似传统的wait()和notify()方法的功能
* 一个锁内部可以有多个Condition,即有多路等待和通知,比wait和notify方法更强大
* 阻塞队列的实现
* @author zhangyaping050
*/
public class BlockQueue
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();
final Object[] items = new Object[100];
int putptr, takeptr, count;
public void pub(Object x) throws Exception
lock.lock();
try
while(count == items.length)
notFull.await();
items[putptr] = x;
if(++putptr == items.length)
putptr = 0;
++count;
notEmpty.signal();
finally
lock.unlock();
public Object take() throws Exception
lock.lock();
try
while(count == 0)
notEmpty.await();
Object x = items[takeptr];
if(++takeptr == items.length)
takeptr = 0;
--count;
notFull.signal();
return x;
finally
lock.unlock();
public static void main(String[] args)
final BlockQueue queue = new BlockQueue();
new Thread(new Runnable()
@Override
public void run()
for(int i=0; i<100; i++)
try
System.out.println("put "+i);
queue.pub(i);
catch (Exception e)
e.printStackTrace();
).start();
new Thread(new Runnable()
@Override
public void run()
for(int i = 0; i<100; i++)
try
System.out.println(queue.take());
catch (Exception e)
e.printStackTrace();
).start();
以上是关于java线程基础的主要内容,如果未能解决你的问题,请参考以下文章
手把手教你构建源码级组件——Java指定共享线程数目的共享锁