java并行程序基础

新建线程

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)


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值