进程是指运行中的应用程序。每个进程都有自己独立的地址空间(内存空间)。
目前操作系统基本都支持多进程。
线程是轻量级的进程;
线程没有独立的地址空间(内存空间);
线程是由进程创建的(寄生在进程);
一个进程可以拥有多个线程,这就是多线程编程;
线程的5中状态:创建,可运行状态,运行状态;阻塞状态,死亡。
创建,可运行状态:cpu等是否空闲;
可运行状态,运行状态:cpu等是否空闲;
运行状态;阻塞状态:cpu等被别人抢占。
运行状态,死亡。:正常的走完。
只要应用程序涉及到并发就要用到多线程的编程。
在java中一个类要当作线程来使用由两种方式:
1.继承Thread类,实现run方法;
2.实现Runnable接口,重写run方法;
publicclass TestThread extends Thread{
public TestThread(String name) {
super(name);
}
public void run() {
for(int i = 0;i<5;i++){
for(long k= 0; k <100000000;k++);
System.out.println(this.getName()+" :"+i);
}
}
publicstaticvoid main(String[] args) {
Thread t1 = new TestThread("阿三");
Thread t2 = new TestThread("李四");
t1.start(); //开启线程 那么就会调用run方法
t2.start();
}
}
另外:线程中Thread.sleep(1000)睡眠状态其实就是进入阻塞状态。并且释放cpu资源。
/**
* 实现Runnable接口的类
*
* @author leizhimin 2008-9-13 18:12:10
*/
publicclass DoSomethingimplements Runnable {
private String name;
public DoSomething(String name) {
this.name = name;
}
publicvoid run() {
for (int i = 0; i < 5; i++) {
for (long k = 0; k < 100000000; k++) ;
System.out.println(name + ": " + i);
}
}
}
/**
* 测试Runnable类实现的多线程程序
*
* @author leizhimin 2008-9-13 18:15:02
*/
publicclass TestRunnable {
publicstaticvoid main(String[] args) {
DoSomething ds1 = new DoSomething("阿三");
DoSomething ds2 = new DoSomething("李四");
Thread t1 = new Thread(ds1);
Thread t2 = new Thread(ds2);//此处是跟继承Thread的区别,还要创建一个线程对象,才可以调用start方法;多线程的运作,这个就是。
t1.start();
t2.start();
}
}
多线程的运用场景:坦克中的子弹。每隔多少秒,坐标持续变化。
同步问题提出
线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏。
就是多个线程不加控制同时访问一个数据的时候,就会出现不规则的情况。
例如:两个线程ThreadA、ThreadB都操作同一个对象Foo对象,并修改Foo对象上的数据。
publicclass Foo {
privateint x = 100;
publicint getX() {
return x;
}
publicint fix(int y) {
x = x - y;
return x;
}
}
publicclass MyRunnableimplements Runnable {
private Foo foo =new Foo();
publicstaticvoid main(String[] args) {
MyRunnable r = new MyRunnable();
Thread ta = new Thread(r,"Thread-A");
Thread tb = new Thread(r,"Thread-B");
ta.start();
tb.start();
}
publicvoid run() {
for (int i = 0; i < 3; i++) {
this.fix(30);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " :当前foo对象的x值= " + foo.getX());
}
}
publicint fix(int y) {
return foo.fix(y);
}
}
运行结果:
Thread-A : 当前foo对象的x值= 40
Thread-B : 当前foo对象的x值= 40
Thread-B : 当前foo对象的x值= -20
Thread-A : 当前foo对象的x值= -50
Thread-A : 当前foo对象的x值= -80
Thread-B : 当前foo对象的x值= -80
Process finished with exit code 0
从结果发现,这样的输出值明显是不合理的。原因是两个线程不加控制的访问Foo对象并修改其数据所致。
如果要保持结果的合理性,只需要达到一个目的,就是将对Foo的访问加以限制,每次只能有一个线程在访问。这样就能保证Foo对象中数据的合理性了。
在具体的Java代码中需要完成一下两个操作:
把竞争访问的资源类Foo变量x标识为private;
同步哪些修改变量的代码,使用synchronized关键字同步方法或代码。
public int fix(int y) {
synchronized (this) {
x = x - y;
}
return x;
}
采用synchronized保卫代码块就可以防止上述的状况,他的原理就是对象锁,排队上厕所,第一个线程完成啦,把门打开,第二个线程才可以用。
对象(this)里面可以换成任何类的对象,看门狗的意思,默认与0与1的标识。1表示为空,可以进入门。2表示有人。this指当前类。
线程死锁 :就是第一个线程完了之后但是没有把0变成1就走啦,导致后面的线程在继续的排队。
共同学习,写下你的评论
评论加载中...
作者其他优质文章