可以使用 Runable 实现类来创建线程,可以共享一个 target 。
不太常用继承Thread 类,虽然这样写稍微简单些。
可以使用 Callable 实现类来创建线程,可以接受并返回运行体的返回值,可以共享一个 target 。
- public class ThirdThread implements Callable<Integer>
- {
-
- public Integer call()
- {
- int i = 0;
- for ( ; i < 100 ; i++ )
- {
- System.out.println(Thread.currentThread().getName()
- + " 的循环变量i的值:" + i);
- }
-
- return i;
- }
-
- public static void main(String[] args)
- {
-
- ThirdThread rt = new ThirdThread();
-
- FutureTask<Integer> task = new FutureTask<Integer>(rt);
- for (int i = 0 ; i < 100 ; i++)
- {
- System.out.println(Thread.currentThread().getName()
- + " 的循环变量i的值:" + i);
- if (i == 20)
- {
-
- new Thread(task , "有返回值的线程").start();
- }
- }
- try
- {
-
- System.out.println("子线程的返回值:" + task.get());
- }
- catch (Exception ex)
- {
- ex.printStackTrace();
- }
- }
- }
suspend() 方法可以将线程挂起,由运行状态切换到阻塞状态。resume() 方法可以使线程重新开始,即由阻塞的状态切换到就绪的状态。
注:已经死亡的线程不可重新开始。
Join 线程:一个线程中,有另一个线程调用join()方法,则原来的线程必须等到新加入的线程结束后才可执行。
还有限制等待时间的方法 join(long mills); 若是等了这么久还没有结束,那么就不等了。
若需要给线程设置为后台线程,而且一定要在start之前就设置,调用方法 setDaemon(true); 主线程死亡,则后台线程也会死亡。
前台线程创建的线程默认为前台线程,后台创建的线程默认为后台线程。
yield()方法会暂时让步给优先级更高的线程(设置线程优先级 setPriority(1~10) )由执行状态切换到就绪状态,若没有优先级更高的,相当于啥也没做。
这个不太常用,常用的是sleep()
同步代码块
synchronized(obj) { //里面写代码,表示给obj加锁,后执行此代码块 }
或者修饰方法,表示同一个对象,此方法不会同时执行。
同步锁
和同步方法有点类似,类中Field 定义锁对象private final ReentrantLock lock = new ReentrantLock(); 可重入锁的实现类,同一时间只能有一个对象可以进入临界区,ReentrantReadWriteLock 读写锁实现类。
-
- lock.lock();
- try
- {
-
- if (balance >= drawAmount)
- {
-
- System.out.println(Thread.currentThread().getName()
- + "取钱成功!吐出钞票:" + drawAmount);
- try
- {
- Thread.sleep(1);
- }
- catch (InterruptedException ex)
- {
- ex.printStackTrace();
- }
-
- balance -= drawAmount;
- System.out.println("\t余额为: " + balance);
- }
- else
- {
- System.out.println(Thread.currentThread().getName()
- + "取钱失败!余额不足!");
- }
- }
- finally
- {
-
- lock.unlock();
- }
一段被锁保护的代码可以调用另一个被相同锁保护的方法。线程间通信:
传统间线程通信
1.wait()方法:当前线程等待,直到其它线程调用该同步监视器的 notify() 方法或 notifyAll() 来唤醒该线程。
2.notify()方法,唤醒一个正在等待的线程。
3.notifyAll()方法,唤醒全部正在等待的线程。
- try
- {
-
- if (!flag)
- {
- wait();
- }
- else
- {
-
- System.out.println(Thread.currentThread().getName()
- + " 取钱:" + drawAmount);
- balance -= drawAmount;
- System.out.println("账户余额为:" + balance);
-
- flag = false;
-
- notifyAll();
- }
- }
- catch (InterruptedException ex)
- {
- ex.printStackTrace();
- }
但若是不使用synchronized来保证同步,而直接用Lock对象,系统中不存在隐式的同步监听器,也就不能使用 wait() , notify() , notifyAll() 方法进行线程通信了。
若是使用Lock对象,则需要引入Condition,使用方法condition.await(), condition.singalAll();
-
- private final Lock lock = new ReentrantLock();
-
- private final Condition cond = lock.newCondition();
-
- lock.lock();
- try
- {
-
- if (!flag)
- {
- cond.wait();
- }
- else
- {
-
- System.out.println(Thread.currentThread().getName()
- + " 取钱:" + drawAmount);
- balance -= drawAmount;
- System.out.println("账户余额为:" + balance);
-
- flag = false;
-
- cond.signalAll();
- }
- }
- catch (InterruptedException ex)
- {
- ex.printStackTrace();
- }
-
- finally
- {
- lock.unlock();
- }
以BlockingQueue对象来实现线程间通信。-
- BlockingQueue<String> bq = new ArrayBlockingQueue<>(2);
- bq.put("Java");
- bq.put("Java");
- bq.put("Java");
线程组和未处理的异常一些未处理的异常可以由这个线程所在的线程组来统一处理。
要构造一个属于某个线程组的线程,调用构造器:
- Thread(ThreadGroup group, Runnable target) ;
- Thread(ThreadGroup group, Runnable target, String name) ;
获得一个线程的线程组,直接调用 getThreadGroup() 方法。线程组类ThreadGroup
- class MyExHandler implements Thread.UncaughtExceptionHandler
- {
-
- public void uncaughtException(Thread t, Throwable e)
- {
- System.out.println(t + " 线程出现了异常:" + e);
- }
- }
- public class ExHandler
- {
- public static void main(String[] args)
- {
-
- Thread.currentThread().setUncaughtExceptionHandler
- (new MyExHandler());
- int a = 5 / 0;
- System.out.println("程序正常结束!");
- }
- }
线程池:- public class ThreadPoolTest
- {
- public static void main(String[]args)
- {
- ExecutorService pool =Executors.newFixedThreadPool(10);
- pool.submit(new MyThread());
- pool.submit(new MyThread());
- pool.submit(new MyThread());
- pool.shutdown();
- }
- }
- class MyThread implements Runnable
- {
- int i=0;
- public void run()
- {
- for(;i<100;++i)
- {
- System.out.println(Thread.currentThread().getName()+" "+i);
- }
- }
-
- }
ForkJoinPool 是为了更好地利用多核处理器资源而设计的多线程类。- class PrintTask extends RecursiveAction
- {
-
- private static final int THRESHOLD = 50;
- private int start;
- private int end;
-
- public PrintTask(int start, int end)
- {
- this.start = start;
- this.end = end;
- }
- @Override
- protected void compute()
- {
-
- if(end - start < THRESHOLD)
- {
- for (int i = start ; i < end ; i++ )
- {
- System.out.println(Thread.currentThread().getName()
- + "的i值:" + i);
- }
- }
- else
- {
-
-
- int middle = (start + end) /2;
- PrintTask left = new PrintTask(start, middle);
- PrintTask right = new PrintTask(middle, end);
-
- left.fork();
- right.fork();
- }
- }
- }
- public class ForkJoinPoolTest
- {
- public static void main(String[] args)
- throws Exception
- {
- ForkJoinPool pool = new ForkJoinPool();
-
- pool.submit(new PrintTask(0 , 300));
- pool.awaitTermination(2, TimeUnit.SECONDS);
-
- pool.shutdown();
- }
- }
如果想要返回运算结果,则继承:RecursiveAction<Integer> 就好,然后覆盖父类的compute()时,用返回值Integer替换void。线程相关类:ThreadLocal类,隔离多个线程的数据共享,每个线程都拥有一份资源。
它可以保留线程局部变量,即在不同的线程,就算是同一个对象,也会持有不同的值。
- class Account
- {
-
-
- private ThreadLocal<String> name = new ThreadLocal<>();
-
- public Account(String str)
- {
- this.name.set(str);
-
- System.out.println("---" + this.name.get());
- }
-
- public String getName()
- {
- return name.get();
- }
- public void setName(String str)
- {
- this.name.set(str);
- }
- }
- class MyTest extends Thread
- {
-
- private Account account;
- public MyTest(Account account, String name)
- {
- super(name);
- this.account = account;
- }
- public void run()
- {
-
- for (int i = 0 ; i < 10 ; i++)
- {
-
- if (i == 6)
- {
- account.setName(getName());
- }
-
- System.out.println(account.getName()
- + " 账户的i值:" + i);
- }
- }
- }
- public class ThreadLocalTest
- {
- public static void main(String[] args)
- {
-
- Account at = new Account("初始名");
-
-
-
-
-
-
- new MyTest(at , "线程甲").start();
- new MyTest(at , "线程乙").start ();
- }
- }
为了解决线程不安全的集合,只需要包装下。调用Collections中的一系列静态方法即可 ,举个例子:便可以返回线程安全的 List<T>,应该在创建后立刻包装。
还有在 Java.util.concurrent 包下提供了大量支持高效并发访问的集合接口和实现类。
类名以 Concurrent 开头的集合类,在并发写入时有较好的性能
类名以CopyOnWriter开头的集合类,在并发读取时有较好的性能
转载自:http://blog.csdn.net/qq_33665647/article/details/54575486?locationNum=4&fps=1
0 0