进程:是一个正在被执行的程序,每一个进程都有一个执行顺序,该顺序是一个执行路径,或者叫做控制单元,用于表示内存总的空间。
线程:是一个进程中的一个独立的控制单元,线程在控制着进程是执行。
如何定义一个线程?
Java提供对线程的描述:Thread
创建线程的第一种方式:让自定义的类继承Thread类,并重写当中的run方法
创建线程的第二种方式:实现Runnable接口,重写run方法。
虽然这两种方式都可以创建一个线程,但是推荐用第二种方式,因为Java不支持多继承,这样用继承Thread类的方式会有很大的局限性,而Runnable接口为线程类提供了一个规则,吧线程的特性定义成了一种功能供自定义线程类进行扩展使用,同时用第二种方法把线程代码封装到自己的类中,而不是线程当中,这样程序是扩展性就很好,而第一种方式是吧线程代码封装到了线程内部,局限性比较大。
为什么要重写run方法呢?
因为run方法中封装了线程要执行的代码。而父类Thread或Runnable接口中的run方法的没有具体实现的,所以子类要自定义run方法中要执行的内容。
如何启动线程?
当线程类是继承自Thread类时,用该类对象调用父类的start()方法即可启动线程。
当线程类是实现Runnable接口时,吧该类的对象作为参数传递给Thread对象,并用此Thread对象调用start()方法启动线程。
线程的安全问题
由于系统运行时,CPU对数据的处理是用时间片的方式来进行的,也就是说CPU在各个程序之间进行着快所的切换处理,这就导致了在多线程程序中,一个线程在执行过程中很容易被剥夺执行权而去执行另外一个线程,这时如果两个线程是操作同一个代码块就会出现数据不一致的情况,这种情况对于大数据高并发的程序非常危险。
要解决这个问题,要么要求CPU一直执行一个线程,结束以后再运行其他线程,要么就让一个线程来执行代码库,该线程不执行完毕其他线程不能执行,也就是线程同步。
显然第一种方式是不可能做到的,那么就得用第二种方法来解决。
Java中提供了两种方式来实现这样的功能:第一种是将要被同步处理的代码用一个同步代码块来封装,第二总是将要被同步处理的代码块所在的方法用synchronized关键性修饰,使其具有同步性。
第一种方式的具体格式为:
synchronized(Object obj){
代码块;
}
其中obj为任意对象。
第二中方式的具体格式为:
synchronized 返回值 方法名(){
代码块;
]
第二中同步方式中,当该方法为非静态是,默认同步锁为当前对象,即this,当该方法为静态是,默认同步锁为该类的class字节码文件对象。
线程间的通信:
例子:多生产者-多消费者 第一种方式
/**
* 多生产者-多消费者
* 生产者生产一个,消费者消费一个,
*
* */
class Source{
private String name;
private int count;
boolean flag = false;
public void setDate(String name){
//同步处理,否则出现数据不一致
synchronized (Object.class) {
while(flag){ //多生产者 消费者 用while + notifyAll():唤醒所有线程。
//如果是一共生产者一个消费者可以用if + notify()
try {
Object.class.wait(); //线程等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//生产
this.name = name;
System.out.println(Thread.currentThread().getName() + "NO."
+ count++ + "ProductName:" + name);
flag = true; //改变标记
Object.class.notifyAll(); //唤醒消费者所以线程
}
}
public void consume(){
synchronized(Object.class){
while(!flag){
try{
//线程等待
Object.class.wait();
}catch(Exception e){}
}
System.out.println(Thread.currentThread().getName() + "NO." + (count-1) + "Name:" + name);
flag = false; //改变标记
Object.class.notifyAll(); //唤醒生产者线程
}
}
}
/**
* 定义生产者线程
* */
class Producer implements Runnable{
private Source s;
public Producer(Source s){
this.s = s;
}
public void run(){
while(true){
s.setDate("商品");
}
}
}
/**
* 定义消费者线程
* */
class Consumer implements Runnable{
private Source s;
public Consumer(Source s){
this.s = s;
}
public void run(){
while(true){
s.consume();
}
}
}
public class ThreadDemoSeven {
public static void main(String []args){
Source s = new Source();
Producer p = new Producer(s);
Consumer c = new Consumer(s);
//创建两个生产线程,两个消费线程
Thread t1 = new Thread(p,"Producer");
Thread t2 = new Thread(p,"Producer");
Thread t3 = new Thread(c,"Consumer");
Thread t4 = new Thread(c,"Consumer");
//启动线程
t1.start();
t2.start();
t3.start();
t4.start();
}
}
第二张方式:运用jdk1.5提供的Lock类,可以更灵活的实现线程通信
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Sources{
private String name;
private int count;
boolean flag = false;
//定义一个线程锁
private Lock lock = new ReentrantLock();
//一个锁上可以有多个Condition进行标记
private Condition condition_pro = lock.newCondition(); //生产线程锁
private Condition condition_con = lock.newCondition(); //消费线程锁
public void setDate(String name) throws InterruptedException{
//加锁
lock.lock();
try {
while (flag) {
//让生产线程进入等待
condition_pro.await();
}
this.name = name;
System.out.println(Thread.currentThread().getName() + "NO."
+ count++ + "ProductName:" + name);
flag = true; //改变标记
condition_con.signal(); //唤醒消费线程
} finally {
lock.unlock();
}
}
public void consume() throws InterruptedException{
//加锁
lock.lock();
try {
while (!flag) {
condition_con.await(); //消费线程进入等待
}
System.out.println(Thread.currentThread().getName() + "NO."
+ (count - 1) + "Name:" + name);
flag = false;
//唤醒生产线程
condition_pro.signalAll();
} finally {
lock.unlock();
}
}
}
/**
* 定义线程类
* */
class Producers implements Runnable{
private Source s;
public Producers(Source s){
this.s = s;
}
public void run(){
try {
while (true) {
s.setDate("商品");
}
} catch (Exception e) {
}
}
}
class Consumers implements Runnable{
private Source s;
public Consumers(Source s){
this.s = s;
}
public void run(){
try {
while (true) {
s.consume();
}
} catch (Exception e) {
}
}
}
/**
* 测试类
* */
public class LokeDemoOne {
public static void main(String []args){
Source s = new Source();
Producer p = new Producer(s);
Consumer c = new Consumer(s);
//四个线程,两个消费线程,两个生产线程
Thread t1 = new Thread(p,"Producer");
Thread t2 = new Thread(p,"Producer");
Thread t3 = new Thread(c,"Consumer");
Thread t4 = new Thread(c,"Consumer");
//启动
t1.start();
t2.start();
t3.start();
t4.start();
}
}