新建线程
start方法创建线程
Thread t1 = new Thread();
t1.start();
不要用run方法开启新线程,它只会在当前线程中,串行执行run方法
重载run方法,执行任务
public static void main(String[] args) {
Thread t1 = new Thread(){
@Override
public void run(){
System.out.println("t1");
}
};
t1.start();
}
单继承Thread,runable接口是一个单方法接口,只有一个run方法
public interface Runnable {
public abstract void run();
}
Thread类有个非常重要的构造方法
public Thread(Runnable target)
它传入一个runnable接口的实例,在start方法调用时,新的线程就会执行Runnable.run()方法
默认的Thread.run()方法
@Override
public void run() {
if (target != null) {
target.run();
}
}
默认的Thread.run()就是直接调用内部的Runnable接口,因此使用Runnable接口告诉线程该做什么,更合理
public class CreateThread3 implements Runnable{
public static void main(String[] args) {
Thread t1 = new Thread(new CreateThread3());
t1.start();
}
@Override
public void run() {
System.out.println("1");
}
}
终止线程
stop会让正在运行的线程释放锁
public class StopThreadUnsafe {
public static User u=new User();
public static class User{
private int id;
private String name;
public User() {
id = 0;
name = "0";
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + "]";
}
}
public static class ChangeObjectThread extends Thread{
@Override
public void run(){
while(true){
synchronized (u) {
int v = (int) (System.currentTimeMillis()/1000);
u.setId(v);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
u.setName(String.valueOf(v));
}
Thread.yield();
}
}
}
public static class ReadObjectThread extends Thread{
@Override
public void run(){
while(true){
synchronized (u) {
if(u.getId() != Integer.parseInt(u.getName())){
System.out.println(u.toString());
}
}
Thread.yield();
}
}
}
public static void main(String[] args) throws InterruptedException {
new ReadObjectThread().start();
while(true){
Thread thread=new ChangeObjectThread();
thread.start();
Thread.sleep(150);
thread.stop();
}
}
}
User [id=1500703032, name=1500703031]
User [id=1500703032, name=1500703031]
User [id=1500703032, name=1500703031]
定义标记变量,表明线程是否需要退出。这个方法被调用,表明线程结束
public static class ChangeObjectThread extends Thread{
volatile boolean stopme = false;
public void stopMe(){
stopme = true;
}
@Override
public void run(){
while(true){
if(stopme){
System.out.println("exit by stop me");
break;
}
synchronized (u) {
int v = (int) (System.currentTimeMillis()/1000);
u.setId(v);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
u.setName(String.valueOf(v));
}
Thread.yield();
}
}
}
线程中断
不会让线程立刻停止,而是通知,线程自行决定啥时退出
线程中断方法
public void Thread.interrupt()//中断线程
public boolean Thread.isInterrupted()//判断是否中断
public static boolean Thread.interrupted()//判断是否被中断,并清除当前中断状态
Thread.interrupt()是个实例方法,通知目标线程中断,设置中断标志位
public void interrupt() {
if (this != Thread.currentThread())
checkAccess();
synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
interrupt0(); // Just to set the interrupt flag
b.interrupt(this);
return;
}
}
interrupt0();
}
Thread.isInterrupted()也是实例方法,判断当前线程是否被中断,通过检查中断标志位
public boolean isInterrupted() {
return isInterrupted(false);
}
Thread.interrupted()判断当前线程中断状态,清除当前线程中断标志位状态
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
下面不会中断,虽然进行了中断,但没有中断逻辑
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(){
@Override
public void run(){
while(true){
Thread.yield();
}
}
};
t1.start();
t1.sleep(2000);
t1.interrupt();
}
增加相应中断代码,则会中断
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(){
@Override
public void run(){
while(true){
if(Thread.currentThread().isInterrupted()){
System.out.println("Interruted!");
break;
}
Thread.yield();
}
}
};
t1.start();
t1.sleep(2000);
t1.interrupt();
}
Thread.sleep()函数
public static native void sleep(long millis) throws InterruptedException;
Thread.sleep()由于中断抛出异常,会清除中断标记,不加处理,在下一次循环开始无法捕获这个中断,所以在异常处理中心,再次设置中断标记位
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(){
@Override
public void run(){
while(true){
if(Thread.currentThread().isInterrupted()){
System.out.println("Interruted!");
break;
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
System.out.println("Interruted When Sleep");
//设置中断状态
Thread.currentThread().interrupt();
}
Thread.yield();
}
}
};
t1.start();
t1.sleep(2000);
t1.interrupt();
}
wait和notify
Object类中的方法
方法签名
public final void wait() throws InterruptedException {
wait(0);
}
public final native void notify();
Object.wait()必须包含在对应的synchronzied语句中,无论wait还是notify都需要首先获得目标对象的一个监视器
下述代码,T1执行object.wait()方法之前先获得object对象锁,然后等待,释放锁,T2执行notify()之前也会先获得对象锁,T2通知T1继续执行后,T1并不能立即执行,要等T2释放object锁,并重新获得锁后,才能继续执行
public class SimpleWN {
final static Object object = new Object();
public static class T1 extends Thread {
@Override
public void run() {
synchronized (object) {
System.out.println(System.currentTimeMillis() + ":T1 start!");
try {
System.out.println(System.currentTimeMillis() + ":T1 wait for object");
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis() + ":T1 end");
}
}
}
public static class T2 extends Thread {
@Override
public void run() {
synchronized (object) {
System.out.println(System.currentTimeMillis() + ":T2 start! notify one thread");
object.notify();
System.out.println(System.currentTimeMillis() + ":T2 end");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
}
}
}
public static void main(String[] args) {
Thread t1 = new T1();
Thread t2 = new T2();
t1.start();
t2.start();
}
}
Object.wait()会释放锁,Thread.sleep()不会释放锁
挂起和继续执行线程
挂起suspend必须等待继续执行resume之后,才能继续指定
这俩方法被废弃了
suspend()导致线程暂停时不会释放任何锁资源,其他线程无法执行,必须对应的线程进行resume()之后,被挂起的线程才能继续,如果resume()提前执行,会永久挂起
public class BadSuspend {
public static Object u= new Object();
static ChangeObjectThread t1 = new ChangeObjectThread("t1");
static ChangeObjectThread t2 = new ChangeObjectThread("t2");
public static class ChangeObjectThread extends Thread{
public ChangeObjectThread(String name){
super.setName(name);
}
@Override
public void run(){
//对临界区的访问
synchronized (u) {
System.out.println("in "+getName());
Thread.currentThread().suspend();
}
}
}
public static void main(String[] args) throws InterruptedException {
t1.start();
Thread.sleep(100);
t2.start();
t1.resume();
t2.resume();
t1.join();
t2.join();
}
}
上述程序不会退出,t2被挂起,由于时间顺序,resume没有生效,导致t2永远被挂起
用wait和notify在应用层实现挂起和执行的例子:
public class GoodSuspend {
public static Object u= new Object();
public static class ChangeObjectThread extends Thread{
//给个标记变量,表示当前线程是否被挂起
volatile boolean suspendme = false;
//用于挂起
public void suspendMe(){
suspendme = true;
}
//用于执行
public void resumeMe(){
suspendme = false;
synchronized (this) {
notify();
}
}
@Override
public void run(){
while(true){
synchronized (this) {
//检查是否挂起,是则等待
while(suspendme){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
synchronized (u) {
System.out.println("in ChangeObjectThread");
}
Thread.yield();
}
}
}
public static class ReadObjectThread extends Thread{
@Override
public void run(){
while(true){
synchronized (u) {
System.out.println("in ReadObjectThread");
}
Thread.yield();
}
}
}
public static void main(String[] args) throws InterruptedException {
ChangeObjectThread t1 = new ChangeObjectThread();
ReadObjectThread t2 = new ReadObjectThread();
t1.start();
t2.start();
Thread.sleep(1000);
t1.suspendMe();
System.out.println("suspend t1 2 sec");
Thread.sleep(2000);
System.out.println("resume t1");
t1.resumeMe();
}
}
等待线程结束join和谦让yield
方法签名:
public final void join() throws InterruptedException {
join(0);
}
public final synchronized void join(long millis) throws InterruptedException
public final synchronized void join(long millis, int nanos) throws InterruptedException
第一个表示无限等待,会一直堵塞当前线程,直到目标线程执行完毕;第二个给出最大等待时间,超过时间,不再等待,继续往下执行
下述不使用join(),线程还没执行,i就被输出,使用join方法,表示主程序愿意等待线程执行完毕,跟着线程一起走,输出9999999
public class JoinMain {
public volatile static int i = 0;
public static class AddThread extends Thread{
@Override
public void run(){
for (int j = 1; j < 10000000; j++){
i= j;
}
}
}
public static void main(String[] args) throws InterruptedException {
AddThread aThread= new AddThread();
aThread.start();
aThread.join();
System.out.println(i);
}
}
join()本质是让调用线程wait()在当前线程对象实例上
join核心代码
while (isAlive()) {
wait(0);
}
它让调用线程在当前线程对象上进行等待,线程执行完成后,被等待的线程会在退出前调用notifyAll通知所有等待线程继续执行,不要在应用程序中,在Thread对象实例上使用类似wait或notify方法,可能影响系统api,或被系统api影响
Thread.yield()
方法签名
public static native void yield();
会使当前线程让出CPU,然后进行CPU资源的争夺
volatile和JAVA内存模型(JMM)
用volatile申明变量,等于告诉虚拟机,这个变量极有可能被某些程序或线程修改,即时通知其他线程
public class MultiTherdLong {
public static volatile long t=0;
public static class ChangeT implements Runnable{
private long to;
public ChangeT(long to){
this.to = to;
}
@Override
public void run() {
while(true){
MultiTherdLong.t = to;
//yield方法,只是人为的通知系统,进行切换, 且有一定机率能切换回本身
Thread.yield();
}
}
}
public static class ReadT implements Runnable{
@Override
public void run() {
while(true){
long tmp=MultiTherdLong.t;
if(tmp!=111L&&tmp!=-999L && tmp!=333L && tmp!=-444L){
System.out.println(tmp);
}
Thread.yield();
}
}
}
public static void main(String[] args) {
new Thread(new ChangeT(111L)).start();
new Thread(new ChangeT(-999L)).start();
new Thread(new ChangeT(333L)).start();
new Thread(new ChangeT(-444L)).start();
new Thread(new ReadT()).start();
}
}
volatile并不能代替锁,无法保证一些复合操作的原子性
如i++
volatile能保证数据的有效性和可见性
下述代码中,ReaderThread线程只有在状态为true时,才会打印number的值,在server下,ReaderThread无法看到主程序的修改,导致ReaderThread永远无法退出,因为while永远为真
public class NoVisibility {
private static boolean ready;
private static int number;
private static class ReaderThread extends Thread{
@Override
public void run(){
while(!ready){
System.out.println(number);
}
}
}
public static void main(String[] args) throws InterruptedException {
new ReaderThread().start();
Thread.sleep(1000);
number = 42;
ready = true;
Thread.sleep(10000);
}
}
用volatile修饰ready就会告诉虚拟机,这个变量可能在不同的线程中修改
线程组
线程多,功能相同的可以放在一个线程组里,注意给线程取名
public class ThreadGroupName implements Runnable{
public static void main(String[] args) {
//建立线程组,加入俩线程
ThreadGroup tGroup= new ThreadGroup("PrintGroup");
new Thread(tGroup,new ThreadGroupName(),"T1").start();
new Thread(tGroup,new ThreadGroupName(),"T2").start();
//获取活动线程的总数,因为线程是动态的,无法确定精确
System.out.println(tGroup.activeCount());
//打印线程组中所有线程信息
tGroup.list();
}
@Override
public void run() {
String groupAndName = Thread.currentThread().getName()+"-"+Thread.currentThread().getName();
while(true){
System.out.println("I am" + groupAndName);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
守护线程(Daemon)
是系统的守护者,在后台默默的完成一系列的服务,比如垃圾回收线程,JIT线程,与之对应的是用户线程,用户线程是系统的工作线程,完成业务操作,用户线程结束,守护线程守护的对象不存在了,整个应用程序就结束,java应用只有守护线程,java虚拟机会自然退出
public class DaemonDemo {
public static class DemonT extends Thread{
@Override
public void run(){
while(true){
System.out.println("I am a alive");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t = new DemonT();
t.setDaemon(true);
t.start();
Thread.sleep(2000);
}
}
设置守护线程必须在start之前,否则有异常说设置失败,但程序仍可执行,只是被当成用户线程。主线程结束,程序也就结束
程序优先级
使用1到10表示线程优先级,使用内置三个静态标量表示
public final static int MIN_PRIORITY = 1;
public final static int NORM_PRIORITY = 5;
public final static int MAX_PRIORITY = 10;
范例:
public class PriorityDemo {
public static class HightPriority extends Thread{
static int count = 0;
@Override
public void run(){
while(true){
synchronized (PriorityDemo.class) {
count++;
if(count>10000000){
System.out.println("HightPriority is complete");
break;
}
}
}
}
}
public static class LowPriority extends Thread{
static int count = 0 ;
@Override
public void run(){
while(true){
synchronized (PriorityDemo.class) {
count++;
if(count>10000000){
System.out.println("LowPriority is complete");
break;
}
}
}
}
}
public static void main(String[] args) {
Thread high = new HightPriority();
Thread low = new LowPriority();
high.setPriority(Thread.MAX_PRIORITY);
low.setPriority(Thread.MIN_PRIORITY);
high.start();
low.start();
}
}
上述代码高优先级的线程大部分情况都会首先完成任务
线程安全的概念和synchronized
volatile并不能保证线程安全,只能确保一个线程修改了数据后,其他线程能够看到这个改动,但当俩个线程同时修改某一个数据时,依然会冲突
public class AccountingVal implements Runnable{
static AccountingVal instance = new AccountingVal();
static volatile int i = 0;
public static void increase(){
i++;
}
@Override
public void run(){
for(int j=0;j<10000000;j++){
increase();
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(instance);
Thread t2 = new Thread(instance);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}
解决问题,要保证多个线程对i进行操作时完全同步
synchronized对同步代码加锁,使得每一次只有一个线程进入同步块,保证线程安全
可以给对象加锁,作用于实例方法,作用于静态方法
public class AccountingValSync implements Runnable{
static AccountingValSync instance = new AccountingValSync();
static volatile int i = 0;
@Override
public void run(){
for(int j=0;j<10000000;j++){
synchronized (instance) {
i++;
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(instance);
Thread t2 = new Thread(instance);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}
synchronized可以保证线程间的有序性和可见性
并发下的ArrayList
是不安全的容器
public class ArrayListMultiThread {
static List<Integer> a1 = new ArrayList<>(10);
public static class AddThread implements Runnable{
@Override
public void run(){
for(int i = 0;i<1000000;i++){
a1.add(i);
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new AddThread());
Thread t2 = new Thread(new AddThread());
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(a1.size());
}
}
可能正常,可能抛异常,是由于ArrayList在扩容时,内部一致性被破坏,没有锁的保护,另一个线程访问到了不一致的内部状态,导致出现越界,还可能打印值作为ArrayList大小
Exception in thread "Thread-1" java.lang.ArrayIndexOutOfBoundsException: 10
at java.util.ArrayList.add(ArrayList.java:459)
at test.ArrayListMultiThread$AddThread.run(ArrayListMultiThread.java:19)
at java.lang.Thread.run(Thread.java:745)
1000002
可以使用Vector代替ArrayList
并发下诡异的HashMap
不安全的
下面代码要么符合预期,要么不好符合预期,要么报错,jdk7可能程序永远无法结束,jdk8不会
public class HashMapMultiThread {
static Map<String, Object> map = new HashMap<>();
public static class AddThread implements Runnable{
int start = 0;
public AddThread(int start){
this.start = start;
}
@Override
public void run(){
for(int i=start;i<100000;i+=2){
map.put(Integer.toString(i), Integer.toBinaryString(i));
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new HashMapMultiThread.AddThread(0));
Thread t2 = new Thread(new HashMapMultiThread.AddThread(1));
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(map.size());
}
}
java.util.HashMap$Node cannot be cast to java.util.HashMap$TreeNode
使用ConcurrentHashMapd代替HashMap
错误的加锁
public class BadLockOnInteger implements Runnable{
public static Integer i=0;
static BadLockOnInteger instance = new BadLockOnInteger();
@Override
public void run(){
for(int j=0;j<10000000;j++){
synchronized (i) {
i++;
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(instance);
Thread t2 = new Thread(instance);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}
I++的执行变成了 I=Integer.valueOf(i.intValue()+1);
Integer.valueOf()是个工厂方法,会返回一个代表指定数值的Integer实例,i++本质就是创建一个新对象,将它的引用赋值给I
因为i对象一直在变,多线程间不一定看到同一个i对象,多个线程加锁就不会在同一个对象实例上
修改
synchronized (i)
为
synchronized (instance)