了解进程和线程
1在多任务系统中,每个独立执行的程序成为进程,也就是“正在进行的程序”。我们现在使用的操作
系统一般都是多任务的,即能够同时执行多个应用程序,实际情况是,操作系统负责对CPU等设备的资源
进行分配和管理,虽然这些设备某一时刻只能做一件事情,但是以非常小的时间间隔交替执行多个程序,
就可以给人以执行多个程序的感觉。
2一个进程又可以包含一个或多个线程,一个线程就是一个程序内部的一条执行线索,如果要一个程序
中实现多段代码同时交替运行,就需要产生多个线程,并指定每个线程上所要运行的程序代码段,这就是
多线程。
用Thread类创建线程
1 要将一段代码在一个新的线程上运行,该代码应该在一个类的run函数中,并且run函数所在的类是
Thread类的子类。倒过来看:我们要实现多线程,必须编写一个继承了Thread类的子类,子类覆盖了
Thread的run()函数,在子类的函数中调用想在新线程上运行的程序代码。
2 启动一个新的线程我们不是直接调用Thread的子类的run()方法,而是调用Thread子类对象的start方
法,start()方法将产生一个新的线程,并在该线程上运行该Thread类对象中的run()方法,根据面向对象
的运行时的多态性,在该线程上实际运行的是Thread子类对象的run()方法。
3由于线程的代码段在run方法中,那么该方法执行完成以后线程也就相应的结束了,因而我们可以通过
控制run方法中的循环条件来控制线程的结束。
后台线程与联合线程
1如果我们对某个线程在启动(调用start())之前调用了setDaemon(true)方法,这个线程就变成了后台
线程。 (2)例子
2对java程序来说,只要还有一个前台线程在运行,这个进程就不会结束,如果一个进程中只有后台线程
运行,这个进程就会结束。(2)例子
3 PP.join()的作用是把pp所对应的线程合并到调用PP.join();语句的线程中。(3)例子
4 实现多线程的另一个方法 创建一个Implements Runnable接口的类,此时线程中所运行的是Runnable
的run方法 (4)例子
(2) 例子:
class ThreadTest extends Thread{
public void run()
{
while(true)
{
System.out.println("run()"+Thread.currentThread().getName());
}
}
public static void main(String[] args) {
Thread tt=new ThreadTest();
tt.setDaemon(true);
tt.start();
/*while (true)
{
System.out.println("main()"+Thread.currentThread().getName());
} */}}
(3)例子
package Hello;
class ThreadTest extends Thread{
public void run(){
while(true){
System.out.println("run()"+Thread.currentThread().getName());
} }
public static void main(String[] args) {
Thread tt=new ThreadTest();
tt.start();
int count=0;
while (true)
{
if(count++ == 100) { //运行100次后合并线程10秒
try {
tt.join(10000);
} catch (Exception e) {
e.printStackTrace();
} }
System.out.println("main()"+Thread.currentThread().getName());
} } }
(4)例子
class ThreadTest implements Runnable//extends Thread{
{ public void run(){
while(true){
System.out.println("run()"+Thread.currentThread().getName());
} }
public static void main(String[] args) {
Thread tt=new Thread(new ThreadTest());
//tt.setDaemon(true);
tt.start();
int count=0;
while (true)
{
if(count++ == 100) {
try {
tt.join(10000);
} catch (Exception e) {
e.printStackTrace();
} }
System.out.println("main()"+Thread.currentThread().getName());
} } }
使用Runnable 接口创建多线程
1 适合多个相同程序代码的线程去处理同一资源的情况,把虚拟CPU(线程) 同程序的代码,数据有效分
离,较好的体现了面向对象的设计思想。
2 可以避免由于java的单继承特性带来的局限。我们将已经继承了一个类的子类放入多线程,由于不能
有两个父类,就不能继承Thread,那么这个类就只能实现Runnable接口。
3 当线程被构造时,需要的代码和数据通过一个对象作为 构造函数的实参传递进去,这个对象就是实现
了Runnable接口的类的实例。
4 事实上,几乎所有的多线程应用都可用Runnable接口方式。
5 例子(5)中 run方法可能在一个线程执行一半时,cpu被分配到了另一个线程,导致同一个票多次售
出。这是我们需要考虑到多线程的同步性。synchronized(str)同步代码块,我们把需要同步的代码放在
代码块中。synchronized后必须传递一个对象(这个对象可以是任意的,但是对象的创建必须在run方法
之外),当线程运行到代码块时,会查看对象的标志位(锁旗标)如果为1则进入代码块,并把标志位改
为0,直到执行完 释放锁旗标(标志位变为1)。
6 除了同步代码块 我们还可以使用同步函数(6)例子
7如何让 同步代码块和同步函数同步呢 (7)例子
例子 编写一个程序实现了四个窗口同时卖100张票。
(5) 同步代码块
public class RunnableTest implements Runnable {
String str=new String("");
int ticket=100;
public void run(){
synchronized(str)
{ if(ticket>0) //同步代码块
System.out.println(Thread.currentThread().getName()+
"is saling ticket "+ ticket--);}}
public static void main(String[] args) {
RunnableTest tt=new RunnableTest();
while(true){
new Thread(tt).start();
new Thread(tt).start();
new Thread(tt).start();
new Thread(tt).start(); }}}
(6)同步函数
public class RunnableTest implements Runnable
{ int ticket=100;
public void run(){
while(true){sale();}
}
public synchronized void sale() {
if(ticket>0)
{System.out.println(Thread.currentThread().getName()+"is saling ticket "+ ticket--);}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
RunnableTest tt=new RunnableTest();
while(true){
new Thread(tt).start();
new Thread(tt).start();
new Thread(tt).start();
new Thread(tt).start(); }}}
(7)代码块和函数同步
public class RunnableTest implements Runnable {
int ticket = 100;
String str = new String("");
public void run() {
if (str.equals("method")) {
while (true) {sale();}
} else {while (true) {synchronized (this)// 同步代码块
{if (ticket > 0) {
System.out.println(Thread.currentThread().getName()+ "is saling ticket " + ticket--);
}}}}}
public synchronized void sale() {
if (ticket > 0) {
System.out.print("sale()");
System.out.println(Thread.currentThread().getName()
+ "is saling ticket " + ticket--);}}
public static void main(String[] args) {
RunnableTest tt = new RunnableTest();
new Thread(tt).start();
tt.str = new String("method");
new Thread(tt).start();}}
** 同步函数 是以this作为锁旗标,所有只要把同步代码块 synchronized(this) 的对象设为this 就
能实现它们的同步。
线程间的通信
1 wait: 告诉当前线程放弃监视器并进入睡眠状态直到其它线程进入同一监视器并调用notify为止
2 notofy: 唤醒同一对象监视器中调用wait的第一个线程。
3 notifyAll: 唤醒同一对象监视器中调用wait的所有线程,具有最高优先级的线程首先被唤醒并执行。
public class Q {
private String name="unknown";
private String sex="unknown";
boolean inFull=false;
public synchronized void put(String name,String sex)
{
if(inFull){
try {
wait();
} catch (Exception e) {
e.printStackTrace();
} }
this.name=name;
this.sex=sex;
inFull=true;
notify();
}
public synchronized void get()
{
if(!inFull)
{
try {
wait();
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.print(name);
System.out.println(":"+sex);
inFull=false;
notify(); }}
public class Producer implements Runnable {
Q q;
public Producer(Q q)
{
this.q=q;
}
public void run() {
int i=1;
while (true) {
if(i==1)
{
q.put("zhangsan", "boy");
}
else
{
q.put("wangwu", "girl");
}}}}
public class Consumer implements Runnable {
Q q;
public Consumer(Q q){
this.q=q;
}
public void run() {
// TODO Auto-generated method stub
while(true)
{
q.get(); } }}
public class ThreadConmunation {
public static void main(String[] args) {
Q q=new Q();
new Thread(new Producer(q)).start();
new Thread(new Consumer(q)).start();
}