public class TestX{ int x; public static void main(String[] args) { TestX t=new TestX(); t.x=5; change(t); System.out.println(t.x); } public static void change(TestX t){ t.x=3; } }
/*我记得是实参往形参传递,且在传递过程中实参值不变。又或是change()函数是API中的一个函数?
不是API里面的,API里面有这个函数,但是是AWT和Swing中使用*/
/*运行结果:3*/
/*摘自红黄书第一章第6个选择题,参看第9面*/
java红黄书P48有疑问?
子类可以直接继承父类的私有属性,但子类不可以直接调用父类的私有方法,子类重写父类的方法,
调用则是子类的方法。
如何重写equals和hashcode方法??看书
多线程(02.12)
单线程:只有一天路径顺序执行的程序。
多线程:并发执行(同一时间端内多条代码执行)。
多线程使用场景:一个程序需要同时执行两个或多个任务,或者,程序需要执行等待的任务时,例如用户输入(比如ATM机),文件读写,网络操作,搜索等。
创建多线程的方法:1.将类定义为java.lang.Thread.的子类并重写run() 2.定义java.lang.Runnable接口的类.
//“重写”run方法?查看API的原始方法。
例子:继承Thread
class MyThread extends Thread{ public void run(){ … } } Thread thread1=new Thread(); //创建新线程就只需要创建该类的实例就行了 例子:实现Runnable方法 class MyRunner implements Runnable{ public void run(){ …. } } MyRunner mr=new MyRunner(); Thread thread2=new Thread(mr);
/*定义好在这个线程中运行的类之后,只需要把它的实例作为参数传入Thread类的构造方法中就可创建一个新线程*/
说明:
一般多用第二种方法,即实现Runnable接口中的方式。
理由是一可以实现多继承,二共享相同的变量资源(比如多个网点实现出售同一车次的票)。
启动线程
要手动启动一个线程,只需要调用Thread实例的start方法即可:
thread1.start();
thread2.start();
完整的多线程自动程序如下所示:
/*创建和启动多个线程*/
class MyThread extends Thread{ public void run(){ for (int i=0;i<100;i++){ System.out.println("MyThread:"+i); } } }
class MyRunner implements Runnable{ public void run(){ for (int i=0;i<100;i++){ System.out.println("MyRunner:"+i); } } }
public class FirstThreadTest{ public static void main(String[] args) { System.out.println("主线程开始执行"); Thread thread1=new MyThread(); System.out.println("启动一个新线程(thread1)..."); thread1.start(); MyRunner mr=new MyRunner(); Thread thread2=new Thread(mr); System.out.println("启动一个新线程(thread2)..."); thread2.start(); System.out.println("主线程执行执行完毕"); } }
2.13
启动线程:thread1.start();
微观视觉:其实每个线程在规定的时间片内执行相应的任务,看起来是同步的,其实严格来讲不是的,
什么时候用多线程?为什么要用多线程?
同一程序要分几段并发执行时(比如ATM机、加载带文字和图片的网页等)。
至于为什么要用多线程,其实相比单线程,多线程JVM要多次调度和管理时必然会浪费更多的时间,但是
为了执行更复杂的操作时候,为了更好的用户体验和安全性(比如加载网页时和ATM机),比如要用户去等待,
让程序出现视觉和感觉上的阻塞,让用户去等待等,为了突破这一技术瓶颈和体验上的瓶颈,必须要用到多线程,
而且也可以提高CPU的执行效率,从整体上减少程序的执行时间。
线程的优先级:
对象.setPriority(Thread.MAX_PRIORITY);//设置最高优先级。
Thread.currentThread().getName()+”:”+i;//返回当前正在执行的线程对象的引用,且返回线程的名称。
线程让步:暂停并让其它线程执行。
用join方法来插入其中,并让该线程执行完毕,再让主线程执行。
同步(synchronized):执行前不被其他线程打断的运行机制叫同步。
2.14
对象锁(用同步来实现)
概念:
同步机制实现主要利用到了“对象锁”。
在JVM中,每个对象和类在逻辑上都是一个监视器相关联的。对于对象而言,关联
的监视器保护的是对象的实例变量;对于类来说,关联的监视器保护的是类的类变量(静态变量)。
如果一个对象里没有实例变量,或没有类变量相关联的监视器就什么也不监视。
特点:
这个锁用来在任何时候被一个线程拥有,且在某刻一个对象只能被一个线程拥有
(相当于只能资源独占,也相当于是一个保护机制,同步也是这个原理,当执行某个操作时,必须要让其把该任务执行完毕,让出资源,才能被另一线程占有)。
加锁方法:
java程序员不用手动为对象执行加锁、解锁的操作。只需要使用同步方法或同步代码块就可以看成是一个
监视器。
另外,存在一个显式加锁机制,用java.util.concurrent.locks.Lock接口提供的lock方法来获取锁,用unlock方法
来释放锁。在实现线程安全的控制中,通常会使用可重入锁ReentrantLock(当线程获得锁之后,其他线程将等待这个锁被释放后才可以
获得这个锁)。
private Lock lock=new ReentrantLock();
//创建Lock实例,其中Lock是父类,而ReeetrantLock是子类对吗?看API,API 中好像没有
…
public boolean sell(){//售票方法,返回是否还有票可以卖? boolean flag=true; lock.lock();//获取锁 if(tickets<100){ tickets=tickets+1;//更改票数 System.out.println(Thread.currentThread().getName()+”:卖出第”+tickets+”张票”); }else{ flag=false; } lock.unlock();//释放锁 try{ Thread.sleep(15); }catch(InterruptException e) {e.printStackTrace();} return flag; }
通常,Lock方式提供了比synchronized代码块更广泛的锁定操作、允许更灵活的结构。因此,
在用java1.5以上的版本写多线程时,建议使用Lock来显式加锁。
线程交互
Object提供的wait和notify(通知、报告)方法
wait方法和notify方法是java同步机制中重要的组成部分,与synchronized关键字结合使用,可以
建立很多优秀的同步模型。
用Timer类调度任务
JDK提供了java.util.Timer类用于定时执行任务。