您的位置:首页 > 编程语言 > Java开发

JAVA--多线程(很重要的呀)

2015-07-17 22:02 441 查看
什么是进程

概念: 正在运行的程序,所占用的内存的空间资源

什么是线程

概述: 线程就是对于CPU的一条独立的执行路径

看成是一个进程中的,多个小程序的独立执行

实现多线程的第一种方式

线程这个事物,也被封装成对象.线程对象的描述类

java.lang.Thread

实现创建新线程步骤

定义类,继承Thread

重写Thread类run方法

创建Thread子类对象

调用的是Thread类的方法start

/*
*  创建新的执行线程
*    定义类继承Thread
*    重写run方法
*    new Thread子类对象
*    调用父类方法start()
*      start 开启线程
*      JVM调用run
*  规范,不管让线程运行什么,请把代码写在run中
*/
class SubThread extends Thread{
public void run(){
for(int x = 0 ; x < 50 ;x++){
System.out.println("run.."+x);
}
}
}

public class ThreadDemo {
public static void main(String[] args) {

SubThread s = new SubThread();
s.start();
for(int x = 0 ; x < 50 ;x++){
System.out.println("main.."+x);
}
}
}


实现多线程第二种方式

实现接口方式 java.lang.Runnable

实现步骤

定义类,实现Runnable接口

重写抽象方法run

创建Thread类对象 ,在Thread类的构造方法中,

传递Runnable接口实现类对象

调用Thread类方法start

/*创建新的执行线程
*    定义类实现接口Runnable
*    重写run方法
*    new 实现接口类对象
*    创建Thread类对象,传递Runnable实现类
*    调用父类方法start()
*      start 开启线程
*      JVM调用run
*  规范,不管让线程运行什么,请把代码写在run中
*/
public class RunnableDemo {
public static void main(String[] args) {
// new 实现接口类对象
RunnableIterface r = new RunnableIterface();
//创建Thread类对象,传递Runnable实现类
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
Thread t3 = new Thread(r);
//调用父类方法start()
t1.start();
t2.start();
t3.start();

}
}
class RunnableIterface implements Runnable{ //定义类实现接口Runnable
public void run() {//重写run方法
System.out.println(Thread.currentThread().getName()+"第二种线程方法~~");
}
}


5 实现线程的两种方式对比

继承Thread

实现Runnable接口

继承Thread,单继承

继承的方式,线程中数据被单个线程独享

实现接口方式,避免了单继承局限性

实现方式,线程中的数据被线程共享

6 同步技术

出现目的,解决线程操作共享数据的安全问题

关键字 synchronized

格式:

synchronized(任意对象){

线程操作的所有共享数据

}

平衡,速度和安全上,保证安全,牺牲速度

任意对象: 监视器 –> 同步锁 – > 锁

线程运行到同步代码块的时候,先判断,判断这个锁还有没有

如果没有,只能等在外面

如果这个所有,有,线程就获取到这个对象锁,进入同步运行

线程出去同步代码块后,对象锁在交还回去

没有锁的线程,不能进入同步执行

上列子~~!

/*
*  要求:
*    多线程技术,模拟储户在银行存钱
*    每次存储100元,分别在两个窗口存,每个窗口存3次
*    余额是0
*      存储的时候余额变化
*        100 200 300 400 500 600
*    一个是银行  存钱的功能
*    一个储户,调用银行的存钱功能,参数
*
*   方法add 代码全是线程共享数据
*   同步整个方法  synchronized加在方法的声明上
*
*   同步方法,同步函数,同步方法只能被一个线程调用,不调用完成,其他线程不能调用
*   同步方法有锁吗,肯定有锁 , 本类对象引用 this
*
*   静态同步方法中,肯定也有锁,锁是谁呢,锁必须是对象
*   对象就是自己类的 class文件 被JVM创建出来的这个对象
*
*   任何一个数据类型 ,JVM都会赋予他一个特别的属性  属性名字 class
*   静态方法中的同步锁,就是自己本类.class属性
*/
class Bank{
private static int sum = 0;
//private Object obj = new Object();
public static synchronized void add(int money){
//synchronized(Bank.class){
sum = sum + money;
System.out.println(sum);
//}
}
}

class Customer implements Runnable{
private Bank b = new Bank();
public void run(){
for(int x = 0 ; x < 3 ; x++){
b.add(100);
}
}
}

public class ThreadDemo9 {
public static void main(String[] args) {
Customer c = new Customer();
Thread t0 = new Thread(c);
Thread t1 = new Thread(c);
t0.start();
t1.start();
}
}


死锁

多个线程,抢夺同一个对象锁,造成程序假死现象

/*
*   多线程,争夺同一个对象锁资源,出现的假死
*   同步的嵌套技术实现
*/
//定义类,实现同步的嵌套
class Dead implements Runnable{
private boolean b;
Dead(boolean b){this.b=b;}
public void run(){
while(true){
//对变量b进行判断,如果b=true,同步嵌套
//线程先进入同步A锁,在进入同步B锁
if(b){
synchronized(LockA.locka){
System.out.println("if...locka");
synchronized(LockB.lockb){
System.out.println("if...lockb");
}
}
}
//变量的值b=false,同步嵌套
//线程先进入同步B锁,在进同步A锁
else{
synchronized(LockB.lockb){
System.out.println("else...lockb");

e8c6
synchronized(LockA.locka){
System.out.println("else...locka");
}
}
}
}
}
}

public class ThreadDead {
public static void main(String[] args) {
Dead d1 = new Dead(true);
Dead d2 = new Dead(false);
Thread t1 = new Thread(d1);
Thread t2 = new Thread(d2);
t1.start();
t2.start();
}
}

//创建2个类,2个类的对象,作为锁使用
class LockA{
public static final LockA locka = new LockA();
}
class LockB{
public static final LockB lockb = new LockB();
}


线程通信

所有的线程,操作的共享数据,必须都同步

必须保证所有的同步使用的锁,唯一的

线程通信中的等待与唤醒机制

生产者生产完成后,需要等待,等待之前唤醒消费者线程

消费者线程打印完后,需要等待,等待之前唤醒生产者线程

程序加了线程的等待和唤醒 Object类的方法 wait notify

抛出 IllegalMonitorStateException异常

无效的监视器状态异常

wait notify 必须有锁的支持

只有锁对象才能调用

/*
* 线程的通信
*   多线程针对同一个学生资源,采用不同类型的数据操作
*   一个线程,负责对学生资源的复制,另一个线程对学生资源负责打印值
*/
//定义学生类,资源对象,姓名,姓别成员即可
class Student  {
String name;
String sex;
boolean flag ;
}
//定义生产者线程,负责对学生赋值
class Product implements Runnable{
private Student s ;
Product(Student s){this.s=s;}
public void run(){
int x = 0 ;
while(true){
synchronized(s){
//判断标记
if(s.flag){
try{s.wait();}catch(Exception ex){}
}
if(x%2==0){
s.name = "张三";
s.sex = "男";
}else{
s.name = "李四";
s.sex = "女";
}
x++;
//修改标记的值
s.flag = true;
//唤醒消费线程
s.notify();
}
}
}
}
//定义消费者线程,负责学生变成获取值
class Customer implements Runnable{
private Student s;
Customer(Student s){this.s=s;};
public void run(){
while(true){
synchronized(s){
//判断标记
if(!s.flag){
try{s.wait();}catch(Exception ex){}
}
System.out.println(s.name+"..."+s.sex);
//修改变量的值
s.flag=false;
//唤醒生产线程
s.notify();
}
}
}
}

public class ThreadDemo {
public static void main(String[] args) {
Student s = new Student();
//创建2个Runnable接口实现类
Product p = new Product(s);
Customer c = new Customer(s);
Thread t0 = new Thread(p);
Thread t1 = new Thread(c);
t0.start();
t1.start();
}
}


这个线程通信中包含了一个唤醒等待机制

线程中的一些小知识点(别小看哦)

为什么wait(),notify(),notifyAll()等方法都定义在Object类中

操作线程的,Thread,为什么不写在Thread类中,出现在Object类中

锁的问题,锁是任意对象,等待还是唤醒必须有锁的支持,只有锁对象才能调用

方法写了最顶层的父类中,任何子类对象,当作锁,都可以调用线程的方法了

Thread类方法sleep 和 Object方法wait有什么区别

sleep 不会释放对象锁

wait 释放对象锁,被唤醒,从新获取锁才能运行

线程池

池技术 pool

有些操作,非常耗时好资源

创建新的线程

JAVA连接数据库服务器

程序开始的时候,创建出锁需要的线程,创建只有1次

容器中保存起来,从容器取出,运行完成后,线程不死,继续回到容器中等待

集合容器

ArrayList

add(t0);

add(t0);

add(t0);

Thread t =array. remove(0);

t.start();

add(t);

JDK5版本,添加使用线程池的功能,内置线程池的概念

工厂类, 负责创建需要的对象

Executors 类负责创建线程池的对象

全部都是静态方法,类名调用

static ExecutorService newCachedThreadPool() 创建新的线程池对象

返回的肯定是接口ExecutorService实现类的对象

static ExecutorService newFixedThreadPool(int nThreads) 创建新的线程池对象,传递int参数

线程池就有指定的线程个数

static ExecutorService newSingleThreadExecutor() 创建线程池对象,池子里面只有1个线程

等同于newFixedThreadPool(1)

ExecutorService 接口方法

submit(Runnable task) 用于执行线程池中的线程,线程去运行Runnable接口实现类的run方法

void run(){

}

Future 获取线程执行后的返回值

Future

submit(Callable task) 用于执行线程池中的线程,运行的是Callable接口的实现类的方法

/*
* 使用JDK5新特性,创建线程池,并且让线程运行起来
*   1. 使用Executors静态方法创建线程池对象
*   2. ExecutorService接口方法 submit执行线程
*   submit(Runnable)
*
*/

class RunnableImpl implements Runnable{
public void run(){
System.out.println(Thread.currentThread().getName());
}
}
public class ThreadPoolDemo {
public static void main(String[] args) {
//使用Executors静态方法创建线程池对象,2个线程的池子
ExecutorService es = Executors.newFixedThreadPool(2);
//调用接口方法submit 传递Runnable接口实现类
es.submit(new RunnableImpl());
es.submit(new RunnableImpl());

//关闭线程池
es.shutdown();
}
}


实现线程的第三种方式

java.util.concurrent.Callable

实现Callable接口,重写call方法

call可以有返回值,可以抛出异常

第三种方式,出现的版本1.5

不要和Thread,Runnable,Callable只能作用在线程池里

Future submit(Callable call)传递Callable接口实现类的对象

submit方法执行完毕后,可以获取到线程运行后的返回值

返回的是Future接口的实现类对象

Future接口方法 get 可以获取到线程执行后的返回值结果

/*
* 实现线程的第三种方式,结合线程池使用
* 线程运行后的结果
*/

//定义类,实现Callable,重写call方法
class CallableImpl implements Callable<String>{
public String call()throws Exception{
System.out.println("执行了call方法");
return "abc";
}
}

public class ThreadPoolDemo1 {
public static void main(String[] args)throws Exception {
//Executors  静态方法创建线程池
ExecutorService es = Executors.newFixedThreadPool(1);
//ExecutorService方法submit运行线程
//submit方法,返回Future接口实现类对象
Future<String> f = es.submit(new CallableImpl());
String s = f.get();
System.out.println(s);

es.shutdown();
}
}


单例设计模式Single

实现思想: 保证一个类的对象,在内存中唯一性

这个是个很有趣的东西~~!

先来个饿汉式的~~!

/*
* 保证Single类,的对象在内存中是唯一性
*   私有构造方法
*     创建对象,是要调用构造方法
*   本类成员位置,创建自己类的对象
*   提供公共访问方式,外类获取对象
*
* 以下写法,成为单例模式 -- 饿汉式
*
*/
public class Single {

private Single(){}
private static Single s = new Single();

public static Single getInstance(){
return s;
}
}


再来个懒汉的~~!

/*
* 保证Single类的对象,在内存中的唯一性
*   懒汉式,对象的延迟加载
*  利用同步保证数据安全,利用双重if判断,提升程序的执行效率
*/
public class Single {
private Single() {
}
private static Single s = null;
public static  Single getInstance() {

if (s == null) {
synchronized (Single.class) {
if (s == null)//这个if是绝对绝对不可以去掉
s = new Single();
}
}
return s;
}
}


然后就是一下线程的方法~~!

* Thread类的方法 setDaemon(boolean )true

* 线程标记为守护线程,必须在start之前使用

* 所有的线程,都是守护线程的时候JVM,就退出

*

* Thread类的方法 static yield 线程的让步

* * 等待该线程终止

*

* Thread类 join

* 执行join方法的线程,会一次性执行完毕

* 其他线程,等我执行完后,抢CPU资源

* 线程的控制方法


* Thread类的静态的方法sleep(long 毫秒值)

* 让执行的线程,在指定的毫秒内,休眠,时间到了,自己醒来继续执行

这个方法要自己try —catch ~~

线程的优先级

* 每个线程都有自己的优先级 1-10

* Thread类方法 int getPriority() 获取线程的优先级

* 优先级高,在用CPU的时间相对更多一些

*

* setPriority(int newPriority) 设置线程的优先级

* Thread类中,提供三个静态成员变量,说明优先级

如何获取,设置线程的名字

每个线程都有自己的名字

Thread-0 -1 -2

获取线程名字

Thread类方法 String getName()

在Thread类用,在Thread子类使用

Thread类,有一个静态方法 currentThread()

返回当前正在运行的线程对象 Thread currentThread()

继续使用线程对象,调用getName方法获取名字

设置线程名字

Thread类的方法 void setName(String name)设置线程名字

Thread类的构造方法(String name)

JDK5新特性,实现线程的加锁和释放锁

java.util.concurrent.locks

接口Lock 实现类ReentrantLock

替代了同步代码块,同步方法的使用

接口方法: lock 获取锁 unlock释放锁

终止线程的2个方式

第一个方式 stop 过时

第二个方式 结束run就可以

void interrupt() 中断线程

比喻:

线程 ->wait永久等待,没有任何线程唤醒你

interrupt让等待线程停止

class Stop implements Runnable{
private boolean flag = true;

public void run(){
while(flag){
synchronized(this){
try{this.wait();}
catch(Exception ex){
ex.printStackTrace();
System.out.println("抓住异常");
flag = false;
}
System.out.println("run...");
}
}
}

public void setFlag(boolean flag){
this.flag =flag;
}
}

public class ThreadStop {
public static void main(String[] args)throws Exception {
Stop s = new Stop();
Thread t0 = new Thread(s);
t0.start();
Thread.sleep(5);
t0.interrupt();
// s.setFlag(false);
}
}


以上方法不分顺序~

还有线程池 线程组!

*Thread类的方法 ThreadGroup getThreadGroup()

*获取线程组对象,返回值是ThreadGroup类的对象

*ThreadGroup类方法 String getName()组的名字

*

*ThreadGroup对线程进行分组管理

* 分组管理一起对一个组中的线程进行统一的设置

*

*ThreadGroup构造方法 传递字符串的组的名字

* 可以自己定义组名,传递给ThreadGroup类构造方法

*

*如何把线程放在线程组中

*Thread类构造方法 第一个参数传递的是线程组的对象

*第二个参数,传递的Runnable接口的实现类对象

使用JDK5新特性,创建线程池,并且让线程运行起来

使用Executors静态方法创建线程池对象

ExecutorService接口方法 submit执行线程

submit(Runnable)

线程这个只是点实在是太乱了~~总结的不好 多多包涵
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: