1.进程和线程的区别:
简单的说,一个程序至少有一个进程,一个进程至少有一个线程,线程的划分尺度小于进程,使得多线程程序的并发性高;
另外,进程在执行过程中拥有独立的内存单元,而多线程共享内存,从而极大提高了程序的运行效率;
线程是进程的一个实体,是CPU调度和分派的基本单元,比进程更小的能独立运行的基本单位;一个线程可以创建和撤销另一个线程;同一个进程中的多个线程可以并发行;
比较:
单线程实例:
它总是按照顺序执行,当方法的调用,转而执行其它方法,完成再回来执行原方法;
public class test{
public static void main(string args[]){
m1();
}
public static void m1(){
m2();
m3();
}
public static void m2(){}
public static void m3(){}
}
多线程实例:使两个进程同时进行,即并发执行;
public class TestThread {
public static void main(String[] args) {
myRunnable rMyRunnable=new myRunnable();
Thread thread=new Thread(rMyRunnable);
thread.start();
for (int i = 0; i < 50; i++) {
System.out.println("mainThread:"+i);
}
}
}
class myRunnable implements Runnable {
public void run() {
for (int i = 0; i < 50; i++) {
System.out.println("myRunnable:"+i);
}
}
}
2.启动线程的两种方式:
第一种:实现Runnable接口
第二种:定义一个类继承Thread类。
举一个实现Runnable接口的实现线程的方式:
public class TestThread {
public static void main(String[] args) {
myRunnable rMyRunnable=new myRunnable();
rMyRunnable.start();
for (int i = 0; i < 50; i++) {
System.out.println("mainThread:"+i);
}
}
}
class myRunnable extends Thread {
public void run() {
for (int i = 0; i < 50; i++) {
System.out.println("myRunnable:"+i);
}
}
}
3.Thread中的方法:
start():使该线程开始执行;Java 虚拟机调用该线程的 run
方法。
sleep():让当前执行的线程沉睡一定的时间;简单的时钟来解释这个sleep()方法和start()方法;
public class TestThread {
public static void main(String[] args) {
myRunnable rMyRunnable=new myRunnable();
rMyRunnable.start();
}
}
class myRunnable extends Thread {
public void run() {
while (true) {
System.out.println("现在时间:"+new Date());
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
4.线程同步问题:
问题:多个线程同时访问同一个资源;
解决的办法:当一个先程访问该资源的时候,不允许其它线程去访问该资源;
synchronized(this){}锁定当前对象,则在一个线程进行时,禁止其它线程来访问;
例子:
public class TestThread implements Runnable{
Test test=new Test();
public static void main(String[] args) {
TestThread testThread=new TestThread();
//启动同一个线程
Thread t1=new Thread(testThread);
Thread t2=new Thread(testThread);
t1.setName("t1");
t2.setName("t2");
t1.start();
t2.start();
}
@Override
public void run() {
//得到当前线程的名字,传给add()方法;
test.add(Thread.currentThread().getName());
}
}
class Test{
private static int num=0;
public void add(String name){
//加上同步锁,保证同一时间只有一个线程可以访问该资源,锁定当前对象;
synchronized (this) {
num++;
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name+"你是第"+num+"个访问此资源的");
}
}
}
举个简单的小例子:数据库中有一条数据,现在又两个方法,一个读数据,一个改数据,那么在该数据的方法上加上同步锁,禁止同时修改数据,但没必要在读数据的方法上加同步锁,可以同时访问。
5.经典的生产者和消费者的问题:
举例:厨司生产馒头,馒头放入篮子中,消费者从篮子中取出馒头吃,这个过程;
public class Test {
public static void main(String[] args) {
LanZi lz=new LanZi();
Producer p=new Producer(lz);
Consumer c=new Consumer(lz);
new Thread(p).start();
new Thread(c).start();
}
}
//定义馒头类
class ManTou {
private int id;
public ManTou(int id) {
this.id = id;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
//重写 toString方法
public String toString() {
return "第"+id+"个馒头";
}
}
//定义篮子类
class LanZi {
int index=0;
//分配数组空间
ManTou[] arrManTous=new ManTou[6];
//放馒头进去方法,加锁锁定资源,保证不能多线程同时访问;
public synchronized void push(ManTou mt){
if (index==arrManTous.length) {
try {
//访问当前对象的线程等待;wait()是object的方法;
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//唤醒等待的线程;
this.notify();
arrManTous[index]=mt;
index++;
}
//取馒头出来方法,加锁锁定资源,保证不能多线程同时访问;
public synchronized ManTou pop(){
if (index==0) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notify();
index--;
return arrManTous[index];
}
}
//定义生产者类
class Producer implements Runnable {
LanZi lz=null;
Producer(LanZi lz){
this.lz=lz;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
ManTou mt=new ManTou(i);
lz.push(mt);
System.out.println("生产了:"+mt);
try {
Thread.sleep((long) (Math.random()*30));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//定义消费者类
class Consumer implements Runnable {
LanZi lz=null;
Consumer(LanZi lz){
this.lz=lz;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
ManTou mt=lz.pop();
System.out.println("消费了:"+mt);
try {
Thread.sleep((long) (Math.random()*3000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}