Java_问题(7——10)


7.abc循环打印十次


  1. package com.multithread.wait;

  2. public class MyThreadPrinter2 implements Runnable {


  3. private String name;

  4. private Object prev;

  5. private Object self;


  6. private MyThreadPrinter2(String name, Object prev, Object self) {

  7. this.name = name;

  8. this.prev = prev;

  9. this.self = self;

  10. }


  11. @Override  

  12. public void run() {

  13. int count = 10;

  14. while (count > 0) {

  15. synchronized (prev) {

  16. synchronized (self) {

  17. System.out.print(name);

  18. count--;


  19. self.notify();

  20. }

  21. try {

  22. prev.wait();

  23. } catch (InterruptedException e) {

  24. e.printStackTrace();

  25. }

  26. }


  27. }

  28. }


  29. public static void main(String[] args) throws Exception {

  30. Object a = new Object();

  31. Object b = new Object();

  32. Object c = new Object();

  33. MyThreadPrinter2 pa = new MyThreadPrinter2("A", c, a);

  34. MyThreadPrinter2 pb = new MyThreadPrinter2("B", a, b);

  35. MyThreadPrinter2 pc = new MyThreadPrinter2("C", b, c);



  36. new Thread(pa).start();

  37. Thread.sleep(100);  //确保按顺序A、B、C执行

  38. new Thread(pb).start();

  39. Thread.sleep(100);

  40. new Thread(pc).start();

  41. Thread.sleep(100);

  42. }

  43. }


  先来解释一下其整体思路,从大的方向上来讲,该问题为三线程间的同步唤醒操作,主要的目的就是ThreadA->ThreadB->ThreadC->ThreadA循环执行三个线程。为了控制线程执行的顺序,那么就必须要确定唤醒、等待的顺序,所以每一个线程必须同时持有两个对象锁,才能继续执行。一个对象锁是prev,就是前一个线程所持有的对象锁。还有一个就是自身对象锁。主要的思想就是,为了控制执行的顺序,必须要先持有prev锁,也就前一个线程要释放自身对象锁,再去申请自身对象锁,两者兼备时打印,之后首先调用self.notify()释放自身对象锁,唤醒下一个等待线程,再调用prev.wait()释放prev对象锁,终止当前线程,等待循环结束后再次被唤醒。运行上述代码,可以发现三个线程循环打印ABC,共10次。程序运行的主要过程就是A线程最先运行,持有C,A对象锁,后释放A,C锁,唤醒B。线程B等待A锁,再申请B锁,后打印B,再释放B,A锁,唤醒C,线程C等待B锁,再申请C锁,后打印C,再释放C,B锁,唤醒A。看起来似乎没什么问题,但如果你仔细想一下,就会发现有问题,就是初始条件,三个线程按照A,B,C的顺序来启动,按照前面的思考,A唤醒B,B唤醒C,C再唤醒A。但是这种假设依赖于JVM中线程调度、执行的顺序。


wait和sleep区别

共同点: 
1. 他们都是在多线程的环境下,都可以在程序的调用处阻塞指定的毫秒数,并返回。 
2. wait()和sleep()都可以通过interrupt()方法 打断线程的暂停状态 ,从而使线程立刻抛出InterruptedException。 
   如果线程A希望立即结束线程B,则可以对线程B对应的Thread实例调用interrupt方法。如果此刻线程B正在wait/sleep /join,则线程B会立刻抛出InterruptedException,在catch() {} 中直接return即可安全地结束线程。 
   需要注意的是,InterruptedException是线程自己从内部抛出的,并不是interrupt()方法抛出的。对某一线程调用 interrupt()时,如果该线程正在执行普通的代码,那么该线程根本就不会抛出InterruptedException。但是,一旦该线程进入到 wait()/sleep()/join()后,就会立刻抛出InterruptedException 。 
不同点: 
1. Thread类的方法:sleep(),yield()等 
   Object的方法:wait()和notify()等 
2. 每个对象都有一个锁来控制同步访问。Synchronized关键字可以和对象的锁交互,来实现线程的同步。 
   sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。 
3. wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用 
所以sleep()和wait()方法的最大区别是:
    sleep()睡眠时,保持对象锁,仍然占有该锁;
    而wait()睡眠时,释放对象锁。
  但是wait()和sleep()都可以通过interrupt()方法打断线程的暂停状态,从而使线程立刻抛出InterruptedException(但不建议使用该方法)。

sleep()方法
sleep()使当前线程进入停滞状态(阻塞当前线程),让出CUP的使用、目的是不让当前线程独自霸占该进程所获的CPU资源,以留一定时间给其他线程执行的机会;
   sleep()是Thread类的Static(静态)的方法;因此他不能改变对象的机锁,所以当在一个Synchronized块中调用Sleep()方法是,线程虽然休眠了,但是对象的机锁并木有被释放,其他线程无法访问这个对象(即使睡着也持有对象锁)。
  在sleep()休眠时间期满后,该线程不一定会立即执行,这是因为其它线程可能正在运行而且没有被调度为放弃执行,除非此线程具有更高的优先级。 
wait()方法
wait()方法是Object类里的方法;当一个线程执行到wait()方法时,它就进入到一个和该对象相关的等待池中,同时失去(释放)了对象的机锁(暂时失去机锁,wait(long timeout)超时时间到后还需要返还对象锁);其他线程可以访问;
  wait()使用notify或者notifyAlll或者指定睡眠时间来唤醒当前等待池中的线程。

  wiat()必须放在synchronized block中,否则会在program runtime时扔出”java.lang.IllegalMonitorStateException“异常。


8、主线程:JVM调用程序main()所产生的进程,名字就是main;

        后台线程:为其他线程提供服务的线程,也叫守护线程,比如GC(JAVA的垃圾回收机制);

        

9.关于Java定时器Timer

schedule(TimerTask task, longdelay)只执行一次,schedule(TimerTask task, long delay, longperiod)才是重复的执行。

Timer是一种工具,线程用其安排以后在后台线程中执行的任务。可安排任务执行一次,或者定期重复执行。Timer实际上是个线程,定时调度所拥有的TimerTasks。 

happysneaker.com

happysneaker.com

如下一个简单的定时器:

import java.util.Timer;
import java.util.TimerTask;
import java.util.Date;

public class MultiThread{
	

	public static void main(String[] args){
		Timer timer = new Timer();
		Task task = new Task();
		timer.schedule(task, new Date(),1000);
	}
}
	
	class Task extends TimerTask{
		@Override
		public void run(){
			System.out.println("dododo...");
		}
	}
//运行结果是从当前时间开始,每隔一秒输出dododo...

分析Timer和TimerTask的源码,原来Timer是一个线程,TimerTask是一个Runnable实现类,那么只要提交TimerTask对象就可以运行任务了。

(要想进行运行线程的任务:需要把对象提交给线程,然后运行方法存在于对象的类中)


更详细的关于Java计时器Timer的在:https://www.cnblogs.com/luckygxf/p/7078662.html


最后总结就是:Timer定时任务原理基本理解,单线程 + 最小堆 + 不断轮询


10.Mysql事务管理

https://my.oschina.net/huangyong/blog/160012

另外:一个事务是一个连续的一组数据库操作。

Unity那些事儿
请先登录后发表评论
  • 最新评论
  • 总共0条评论