1 线程的创建与启动
/**
* Runnable的实现类,是线程执行的主体。
* run函数是入口
* @author Administrator
*
*/
class MyRimplements Runnable{
private String msg;
public MyR(String msg) {
this.msg=msg;
}
@Override
public void run() {
while(true) {
try {
Thread.sleep(1000);
System.out.println(msg);
} catch(InterruptedException e) {
e.printStackTrace();
break;
}
}
}
}
public classTestThread {
public static void main(String[] args) {
Thread thread1 =new Thread(newMyR("hello"));
thread1.start();
Thread thread2 =new Thread(newMyR("heihei"));
thread2.start();}
}1):定义一个类A..
2):在A类中覆盖Thread类中的run方法.
3):我们在run方法中编写需要执行的操作:run方法里的代码,线程执行体.
4):在main方法(线程)中,创建线程对象,并启动线程.
(1)创建线程类对象:
A类 a = new A类();
(2)调用线程对象的start方法:
a.start();//启动一个线程
进程:正在运行的程序
线程:有时被称为轻量级进程,是程序执行流的最小单元
区别:1.调度的基本单位:进程是作为独立调度和分派的基单位本
线程是独立运行的基本单位
2.并发性:进程之间可以并发执行,一个进程中的多个线程之间亦可以并发执行。
3.拥有资源:线程不拥有系统资源。
4.独立性:在同一进程中的不同线程之间的独立性要比不同进程之间的独立性低的多。
5.系统开销:在创建或撤销进程时,系统都要为之分配和回收坚持问你个控制块、分配或回收其他资源
6.支持多处理机系统
1)thread1和thread2的线程ID不同,thread2和主线程ID相同,说明通过run方法调用并不会创建新的线程,而是在主线程中直接运行run方法,跟普通的方法调用没有任何区别;
2)虽然thread1的start方法调用在thread2的run方法前面调用,但是先输出的是thread2的run方法调用的相关信息,说明新线程创建的过程不会阻塞主线程的后续执行。
2.实现Runnable接口
在Java中创建线程除了继承Thread类之外,还可以通过实现Runnable接口来实现类似的功能。实现Runnable接口必须重写其run方法。
package zs;
/**
*Runnable的实现类,是线程执行的主体。
*run函数是入口
*@author Administrator
*
*/
class MyR implements Runnable{
privateString msg;
publicMyR(String msg) {
this.msg=msg;
}
@Override
publicvoid run() {
while(true){
try{
Thread.sleep(1000);
System.out.println(msg);
}catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
}
}
public class TestThread {
publicstatic void main(String[] args) {
Threadthread1 =new Thread(new MyR("hello"));
thread1.start();
Threadthread2 =new Thread(new MyR("wuwu"));
thread2.start();
}
}
package zs;
public class TestThread2 {
publicstatic void main(String[] args) {
TestThreadtestThread2=new TestThread();
Runnablerunnable=new Runnable() {
publicvoid run() {
while(true){
try{
Thread.sleep(1000);
System.out.println("haha");
}catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
}
};
Threadthread =new Thread(runnable);
thread.start();
}
}
package zs;
public class TextThread3 {
publicstatic void main(String[] args) {
newThread(new Runnable(){
publicvoid run() {
System.out.println("haha");}
}).start();
newThread(()-> {
System.out.println("haha");
}).start();
}
}1.继承Thread类,重写该类的run()方法。
2.实现Runnable接口,并重写该接口的run()方法,
该run()方法同样是线程执行体,创建Runnable实现类的实例,并以此实例作为Thread类的target来创建Thread对象,该Thread对象才是真正的线程对象。
3.使用Callable和Future接口创建线程。
具体是创建Callable接口的实现类,并实现clall()方法。并使用FutureTask类来包装Callable实现类的对象,且以此FutureTask对象作为Thread对象的target来创建线程。
同步:
是对多个相关进程在执行次序上进行协调,是并发执行的诸进程之间能按照一定规则共享系统资源。
必要性:
如果不能采取有效的措施,对多个进程的运行进行妥善的管理,必然会因为这些进程对系统资源的无序争夺给系统造成混乱。致使每次处理的结果存在着不确定性,即显现出妻不可再现性。
为什么要同步,可以举例说明
为保证多个程序能有条不紊的进行,在多道程序系统中,必须引入进程同步机制。
· 1
· 2
synchronize:关键字synchronize拥有锁重入的功能,也就是在使用synchronize时,当一个线程的得到了一个对象的锁后,再次请求此对象是可以再次得到该对象的锁。
当一个线程请求一个由其他线程持有的锁时,发出请求的线程就会被阻塞,然而,由于内置锁是可重入的,因此如果某个线程试图获得一个已经由她自己持有的锁,那么这个请求就会成功,“重入” 意味着获取锁的操作的粒度是“线程”,而不是调用。
同步块:用来标记方法或者代码块是同步的。Java 同步块用来避免竞争。
Package zs;
importjava.util.ArrayList;
importjavax.swing.text.StyledEditorKit.ForegroundAction;
importcom.sun.media.jfxmedia.events.NewFrameEvent;
public classtest5 {
static int c=0;
private staticObject lock =new Object();//创建一个锁变量
public static void main(String[] args) {
Thread[] threads = new Thread[1000];
for(int i=0;i<1000;i++) {
final int index =i;
threads[i]= new Thread(()->{
synchronized(lock) {//创建一个同步块,需要一个锁
System.out.println("thread"+index+" enter");//输出
int a = c;
a++;
try {
Thread.sleep((long)(Math.random()*1000));
} catch (Exception e) {
e.printStackTrace();
}
c=a;//存回去
System.out.println("thread"+index+" leave");
}
});
threads[i].start();
}
for(int i=0;i<1000;i++) {
try {
threads[i].join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.print("c="+c);
}
}
生产者-消费者问题是一个著名的进程同步问题。他描述的是:有一群生产者进程在生产产品,并将这些产品提供给消费者进程去消费。为使生产者进程与消费者能并发执行,在两者之间设置一个具有n个缓冲池,生产者进程将其所生产的产品放入一个缓冲区中;消费者进程可从一个缓冲区中取走一个产品去消费。尽管所有生产者进程和消费者进程都是以异步方式运行的,但他们之间必须保持同步,既不允许消费者进程放到一个空缓冲区去取产品,也不允许生产者进程向一个一装满产品且尚未被取走的缓冲区中投放产品。
Void producer(){
While(1){
Produce an item in nextp;
………
While(counter==n);
Buffer[in]=nextp;
In=(in+1)%n;
Counter++;
}
};
Void consumer()
{
While(1){
While(counter-==0);
……….
Nextc=buffer[out];
Out=(out+1)%n;
Counter--;
Consumer the item in nextc;
……….
}
};
package zs;
import java.util.LinkedList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
publicclassQueue { //队列
private Lock lock = new ReentrantLock();
private Condition fullC; //信号量
private Condition emptyC; //信号量
privateintsize;
public Queue(intsize) {
this.size = size;
fullC = lock.newCondition();
emptyC = lock.newCondition();
}
LinkedList<Integer>list= newLinkedList<Integer>();
/**
* 入队
* @return
*/
publicboolean EnQueue(intdata) {
lock.lock();
while(list.size()>=size) {
try {
fullC.await();
}catch(InterruptedException e) {
lock.unlock();
returnfalse;
}
}
list.addLast(data);
emptyC.signalAll();
lock.unlock();
returntrue;
}
/**
* 出队
* @return
*/
publicint DeQueue() {
lock.lock();
if(list.size() == 0) {
try {
emptyC.await();
}catch(InterruptedException e) {
lock.unlock();
return -1;
}
}
intr = list.removeFirst();
fullC.signalAll();
lock.unlock();
returnr;
}
publicboolean isFull() {
returnlist.size()>=size;
}
publicboolean isEmpty() {
returnlist.size()==0;
}
}
package zs;
import javax.net.ssl.SSLException;
publicclass zss{
static Queue queue=new Queue(5);
publicstaticvoid main(String[] args) {
for(inti=0;i<3;i++) {
finalintindex=i;
new Thread(()->{
intdata=(int)(Math.random()*1000);
System.out.printf("thread %d want to EnQueue %d\n"+data);
queue.EnQueue(data);
System.out.printf("thread %d EnQueue %d Success\n"+data);
sleep();
}).start();
}
for(inti=0;i<3;i++) {
finalintindex=i;
new Thread(()->{
while(true) {
System.out.printf("customer thread %d want to DcQueue %d\n",index);
intdata = queue.DeQueue();
System.out.printf("customer thread %d Success\n",index);
sleep();
}
}).start();
publicstaticvoid sleep() {
intt=(int)(Math.random()*1000);
try {
Thread.sleep(t);
}
catch(InterruptedException e) {
e.printStackTrace();
}
}
}
produce thread 0 want to EnQueue 406
produce thread 0 EnQueue 406 Success
customer thread 1 want to EnQueue
customer thread 1 EnQueue 406 Success
produce thread 2 want to EnQueue 7551
produce thread 2 EnQueue 7551 Success
customer thread 2 want to EnQueue
customer thread 2 EnQueue 7551 Success
customer thread 0 want to EnQueue
produce thread 1 want to EnQueue 4115
produce thread 1 EnQueue 4115 Success
customer thread 0 EnQueue 4115 Success
produce thread 1want to EnQueue 8
customer thread1 want to EnQueue
produce thread 2want to EnQueue 0
produce thread 2EnQueue 0 Success
customer thread1 EnQueue 0 Success
customer thread2 want to EnQueue
customer thread2 EnQueue 8 Success
customer thread0 want to EnQueue
produce thread 0want to EnQueue 6
produce thread 0EnQueue 6 Success
produce thread 1EnQueue 8 Success
customer thread0 EnQueue 6 Success
通过本次操作系统实践课,我了解了更多的实践中运用的技巧,线程的创建,以及对一些理论中问题的实际认识。线程的同步机制解决多个进程并发运行。特别是线程的三种创建方式,经典的生产者-消费者问题,使我对这些问题的认识,从书本的理论层次到计算机实际运用问题,这里面存在的一系列问题,迎刃而解。使我对这些问题又有了更加深刻的理解。