线程:
线程是程序的执行路径,一个进程包含多条线程
多线程的并发执行可以提高程序的效率,可以同时完成多项工作。
多行程并行和并发的区别
并行的使用 要使用多核CPU
并发指两个任务都运行,而处理器只能接受一个任务,将两个任务轮流执行
Java命令启动java虚拟机,启动JVM等于启动一个进程,该进程会自动启动一个“主线程”,然后主线程去调用某类的main方法
JVM的启动至少启动了垃圾回收线程和主线程,因此JVM是多线程的,注意线程是穿插执行
多线程
1、继承Thread,并且重写Thread的run方法,并分配和启动该子类的实例
public static void main(String[] args) {
MyThread mt = new MyThread();
mt.start();
for (int i = 0; i < 1000; i++) {
System.out.println("xxxxxxx");
}
}
}
class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("测试"+i);
}
}
2、实现Runnable()接口
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
}
}).start();
-------------------------------------------------------------------------
Runnable和Thread的区别
a 继承Thread 由于子类重写了Thread类的run(),调用start()时,直接调用子类的run方法 实现代码简单,但是如果有父类,不能实现Thread。
b 实现Runnable 构造函数中传入Runnable的引用,成员变量通过记住它,start()调用run(方法)判断是否引用为空,如果不为空,编译Runnable的run(),运行时执行子类的run()方法,实现代码复杂,需要先获取到线程对象,才能使用Thread的方法
-------------------------------------------------------------------------
采用匿名内部类实现两种方法
new Thread(
public void run(){
}
).start();
new Thread(new Runnable(){
public void run(){
}
}).start();
--------------------------------------------------------------------
获取
getName() 获取线程名称
new Thread(new Runnable() {
@Override
public void run() {
this.getName();
}
}).start();
setName()可以改变名称或者在构造方法中修改名称
--------------------------------------------------------------------
获取当前线程的对象
Thread t = Thread.CurrentThread();
要使用Runnable接口,可以使用Thread.CurrentThread()获取当前线程;
-------------------------------------------------------------------
线程休眠
Thread.sleep(毫秒,纳秒);
-------------------------------------------------------------------
setDemon 守护线程
设置一个线程为守护线程,该线程不会单独执行,当其他非守护线程都执行结束后,自动退出
当非守护线程都执行结束后,自动退出
--------------------------------------------------------------------
加入线程
join()当前线程暂停,等待指定的线程执行结束后,当加入线程结束后,在继续执行线程
匿名内部类使用局部变量时候,必须用final修饰
使用局部变量
---------------------------------------------------------------------
礼让线程 yield()
---------------------------------------------------------------------
设置线程优先级
norm = 5
min = 1
max = 10
new Thread().setPriority(Thread.MIN_PRIORITY);
---------------------------------------------------------------------
同步代码块
当多段代码同时执行的过程中,我们希望cpu不要切换到其他线程工作,就需要同步操作
synchronized 同步代码块
锁对象是任意的,但是不能使用匿名内部类,因为匿名对象不是同一个对象
public static void main(String[] args) {
new Thread(){
public void run() {
Test t = new Test();
t.print1();
};
}.start();
new Thread(){
public void run() {
Test t = new Test();
t.print2();
};
}.start();
}
}
class Test {
static Lock lock = new Lock();
public static void print1(){
synchronized(lock){
System.out.println("xxxxxxx");
}
}
public static void print2(){
synchronized(lock){
System.out.println("yyyyyyyyy");
}
}
}
class Lock{
public Lock(){
}
}
--------------------------------------------------------------------------
如果同步方法,在方法上加synchronized关键字即可
非静态的同步方法的锁对象是this
静态方法的同步方法锁对象是 Object.class 该类的字节码文件
------------------------------------------------------------------------
线程安全问题
铁路售票问题 共有100张,通过4个窗口买完
如果引用数据类型成员变量当成锁对象,要加静态类型
public class Demo_Ticket {
public static void main(String[] args) {
new Ticket().start();
new Ticket().start();
new Ticket().start();
new Ticket().start();
}
}
class Ticket extends Thread {
private static int ticket = 100;
@Override
public void run() {
while (true) {
synchronized (Ticket.class) {
if (ticket <= 0) {
break;
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(getName() + "....第" + ticket-- + "张");
}
}
}
}
---------------------------------------------------------------------------
Runnable接口实现
---------------------------------------------------------------------------
哲学家筷子问题 (不要出现同步代码块嵌套)
public class Demo_Lock {
private static String s1 = "筷子左";
private static String s2 = "筷子右";
public static void main(String[] args) {
new Thread (new Runnable() {
public void run() {
while (true) {
synchronized(s1){
System.out.println(Thread.currentThread().getName()+"获取"+s1+"等待"+s2);
synchronized(s2){
System.out.println("拿到"+s2+"开吃");
}
}
}
}
}).start();
new Thread (new Runnable() {
public void run() {
while (true) {
synchronized(s1){
System.out.println(Thread.currentThread().getName()+"获取"+s1+"等待"+s2);
synchronized(s2){
System.out.println("拿到"+s2+"开吃");
}
}
}
}
}).start();
new Thread (new Runnable() {
public void run() {
while (true) {
synchronized(s1){
System.out.println(Thread.currentThread().getName()+"获取"+s1+"等待"+s2);
synchronized(s2){
System.out.println("拿到"+s2+"开吃");
}
}
}
}
}).start();
new Thread (new Runnable() {
public void run() {
while (true) {
synchronized(s1){
System.out.println(Thread.currentThread().getName()+"获取"+s1+"等待"+s2);
synchronized(s2){
System.out.println("拿到"+s2+"开吃");
}
}
}
}
}).start();
}
}
Vector是线程安全的
ArrayList 是线程不安全的
StringBuffer 是线程安全的
StringBuilder 是线程不安全的
HashTable是线程安全的 HashMap是线程不安全的
将不安全的线程变成安全的 用类Collections
单例设计模式
public class Demo_SIngleton {
// 保证内存中只有一个对象
public static void main(String[] args) {
// Singleton s1 = new Singleton();
/*Singleton s1 = Singleton.s;
Singleton s2 =Singleton.s;
System.out.println(s1==s2);*/
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
System.out.println(s1==s2);
}
}
// 饿汉式 直接创建对象比较好 空间换时间 不会创建多个对象
class Singleton{
// 私有构造,其他类不能访问该构造方法
private Singleton(){}
// 创建本类对象 成员变量私有,不能调用
private static Singleton s = new Singleton();
// 对外提供公共的访问方法
public static Singleton getInstance(){
return s;
}
}
//懒汉式 会出现多线程的问题 时间换空间 有可能创建多个对象
class Singleton2{
// 私有构造,其他类不能访问该构造方法
private Singleton2(){}
// 创建本类对象 成员变量私有,不能调用
private static Singleton2 s ;
// 对外提供公共的访问方法
public static Singleton2 getInstance(){
if (s == null){
s = new Singleton2();
}
return s;
}
}
//
class Singleton3{
// 私有构造,其他类不能访问该构造方法
private Singleton3(){}
// 创建本类对象 成员变量私有,不能调用
private static final Singleton3 s = new Singleton3();;
// 对外提供公共的访问方法
public static Singleton3 getInstance(){
return s;
}
}
-----------------------------------------------------------------------------------
Runtime类
import java.io.IOException;
public class Demo_Runtime {
public static void main(String[] args) throws IOException {
//获取运行时对象
Runtime runTime = Runtime.getRuntime();
//执行字符串命令
//runTime.exec("shutdown -s -t 300");
runTime.exec("shutdown -a");
}
}
-------------------------------------------------------------------------------------
Timer 类(参数1:安排的任务 参数2:执行的时间 参数3:过多久再执行一次)
线程安排在后台执行任务,或者定期重复执行,指定时间安排指定任务
public class Demo_Timer {
public static void main(String[] args) throws InterruptedException {
Timer t = new Timer();
t.schedule(new MyTimerTask(),new Date(108,0,31,10,48,0), 5000);
while(true){
Thread.sleep(1000);
System.out.println(new Date());
}
}
}
class MyTimerTask extends TimerTask{
@Override
public void run() {
System.out.println("起床");
}
}
--------------------------------------------------------------------------------------
两个线程的通信(交替执行)
public class Demo_ThreadCommuicate {
//等待唤醒机制 wait() notify()
public static void main(String[] args) {
final Printer p = new Printer();
new Thread(){
public void run(){
while (true) {
try {
p.print1();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}.start();
new Thread(){
public void run(){
while (true) {
try {
p.print2();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
}
class Printer{
private int flag = 1;
public void print1() throws InterruptedException {
synchronized(this){
if(flag!=1){
this.wait();
}
System.out.print("A");
System.out.print("B");
System.out.print("\r\n");
flag = 2;
this.notify();
}
}
public void print2() throws InterruptedException {
synchronized(this){
if(flag!=2){
this.wait();
}
System.out.print("Z");
System.out.print("W");
System.out.print("\r\n");
flag = 1;
this.notify();
}
}
}
-------------------------------------------------------------------------------
三个或三个以上线程的通信 notify()是随即唤醒线程
public class Demo_notifyAll {
public static void main(String[] args) {
final Printer2 printer2 = new Printer2();
new Thread(){
public void run() {
while(true){
try {
printer2.print1();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};}.start();
new Thread(){
public void run() {
while(true){
try {
printer2.print2();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};}.start();
new Thread(){
public void run() {
while(true){
try {
printer2.print3();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};}.start();
}
}
class Printer2{
private int flag = 1;
public void print1() throws InterruptedException{
synchronized(this){
while(flag!=1){
this.wait();
}
System.out.print("A");
System.out.print("B");
System.out.print("\r\n");
flag = 2;
this.notifyAll();
}
}
public void print2() throws InterruptedException{
synchronized(this){
while (flag!=2){
this.wait();
}
System.out.print("M");
System.out.print("N");
System.out.print("\r\n");
flag = 3;
this.notifyAll();
}
}
public void print3() throws InterruptedException{
synchronized(this){
while(flag!=3){
this.wait();
}
System.out.print("Z");
System.out.print("W");
System.out.print("\r\n");
flag = 1;
this.notifyAll();
}
}
} }
}
注意事项:
在同步中,用什么对象作锁,就用什么对象wait()和notify()
wait方法和notify定义在Object,因为锁对象可以是任意对象,而Object是所有对象的基类
Sleep和wait的区别
sleep必须传入参数,参数就是时间,时间到,自动唤醒
wait方法,可以传入参数,也可以不传入参数,传入参数就是在参数的时间结束后等待,不传入参数就是直接等待
Sleep方法在同步函数或者同步代码块中,不释放锁
wait方法在同步代码块或者同步函数中,释放锁
------------------------------------------------------------------------------
JDK1.5 互斥锁
ReentrantLock类的lock() unlock()替换synchronized
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class Demo_Lock {
public static void main(String[] args) {
final Printer3 p3 = new Printer3();
new Thread(){
public void run() {
while(true){
try {
p3.print1();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};}.start();
new Thread(){
public void run() {
while(true){
try {
p3.print2();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};}.start();
new Thread(){
public void run() {
while(true){
try {
p3.print3();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};}.start();
}
}
class Printer3 {
private ReentrantLock r = new ReentrantLock();
private int flag = 1;
private Condition c1 = r.newCondition();
private Condition c2 = r.newCondition();
private Condition c3 = r.newCondition();
public void print1() throws InterruptedException {
r.lock();
while (flag != 1) {
c1.await();
}
System.out.print("A");
System.out.print("B");
System.out.print("\r\n");
flag = 2;
c2.signal();
r.unlock();
}
public void print2() throws InterruptedException {
r.lock();
while (flag != 2) {
c2.await();
}
System.out.print("M");
System.out.print("N");
System.out.print("\r\n");
flag = 3;
c3.signal();
r.unlock();
}
public void print3() throws InterruptedException {
r.lock();
while (flag != 3) {
c3.await();
}
System.out.print("Z");
System.out.print("W");
System.out.print("\r\n");
flag = 1;
c1.signal();
r.unlock();
}
}
lock()上锁
unlock()解锁
Condition c = r.newCondition();
c.await() == this.wait()
c.singnal() == this.notifyAll() 可以指定线程而无需全部唤醒
----------------------------------------------------------------
线程组的概述和使用
TreadGroup 表示线程组,允许对一群线程组管理 Java允许其对线程组管理
public class Demo_ThreadGroup {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread t1 = new Thread(myRunnable,"张三");
Thread t2 = new Thread(myRunnable,"李四");
ThreadGroup tg1 = t1.getThreadGroup();//默认是主线程
System.out.println(tg1.getName());
ThreadGroup tg2 = t2.getThreadGroup();//默认是主线程
System.out.println(tg2.getName());
//如何设置线程组
ThreadGroup tg = new ThreadGroup("我是新的线程组");
MyRunnable mr = new MyRunnable();
Thread t3 = new Thread(tg,mr,"张三");
Thread t4 = new Thread(tg,mr,"李四");
Thread t5 = new Thread(tg,mr,"王五");
System.out.println(t3.getThreadGroup().getName());
tg.setDaemon(true);
}
}
class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println(Thread.currentThread().getName()+"..."+i);
}
}
}
------------------------------------------------------------------
线程的五种状态
线程的生命周期:
新建 创建线程对象
就绪 想成对象已经启动,但未获得CPU执行权
运行 获得CPU执行权
阻塞 没有CPU执行权,回到就绪
死亡 代码运行完毕,线程消亡
-------------------------------------------------------------------
线程池的概述和使用
使用线程池能够很好提高性能,尤其当程序中创建大量生命周期较短的线程时,更要考虑线程池,线程池中的代码结束后,并不会死亡,而是返回线程池变成空闲状态,
Java内置的线程池Executors工厂类来产生线程吃 有以下方法
public static ExecutorService newFixedThreadPool(int nThreads)
public static ExecutorService newSingleThreadExecutor()
这些方法返回的是ExecutorService对象,可以执行Runnable对象或者Callable对象代表的线程们提供了
Future<?> submit(Runnable task)
<T> Future<T submit(Callable<T> task)
创建步骤:
创建线程池对象
创建Runnable实例
提交Runnbale实例
关闭线程池
// 创建线程池
ExecutorService pool = Executors.newFixedThreadPool(2);
pool.submit(new MyRunnable());//将县城放入池中并并行
pool.submit(new MyRunnable());
pool.shutdown();//关闭线程池
-----------------------------------------------------------------------------
多线程(多线程程序实现的方式)
提交的是Callable
import java.util.Iterator;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class Demo_Callable {
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService pool = Executors.newFixedThreadPool(2);
Future<Integer> f1 = pool.submit(new MyCallable(100));
System.out.println(f1.get());
Future<Integer> f2 = pool.submit(new MyCallable(50));
System.out.println(f2.get());
pool.shutdown();
}
}
class MyCallable implements Callable<Integer>{
private int num ;
public MyCallable(int num) {
this.num = num;
}
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 0; i <= num; i++) {
sum+=i;
}
return sum;
}
}
------------------------------------------------------------------------------------------------
简单工厂模式
称为 静态工厂方法模式,定义一个具体工厂类来创建类的实例
优点:客户端不需要在负责对象的创建,从而明确了各个类的职责
缺点:该静态工厂负责所有类的创建,如果有对象增加,或者修改对象创建方式,就要不断的修改工厂类,不利于维护啊
-------------------------------------------------------------------------------------------------
工厂方法模式 (抽象工厂类负责定义创建对象的接口,具体对象的创建工作由继承抽象工厂的具体类实现)
将工厂类抽取成接口,对不同的对象生成不同的工厂来生产产品
public interface Factory {
public Animal createAnimal();
}
public class DogFactory implements Factory {
@Override
public Animal createAnimal() {
return new Dog();
}
}
----------------------------------------------------------------------------------------------------
GUI界面显示
Graphical User Interface
Frame f = new Frame("xxxx");
f.setLayout();
f.setSize(400,600);
f.setLocation(300,50);
f.setIcomImage(Toolkit.getDefaultToolkit().createImage());
FlowLayout 流式布局管理器
BorderLayout 边界布局管理器
GridLayout 网格布局管理器
CardLayout 卡片布局管理器
GridBagLayout 网格背包管理器
f.setVisible(true);//设置窗体可见
GUI布局管理器
-----------------------------------------------------------------------------------------------------
窗体的监听
f.addWindowListener(); //windowAdapter 实现了WIndowListener,并且重写了空方法
鼠标监听
f.addMouseListener(); MouseAdapter重写部分方法
键盘监听
f.addKeyListener(); KeyAdapter()适配监听 Event.VK_Z
动作监听
button.addActionListener 执行actionPerFormed(ActionEvent e)//添加动作场景
--------------------------------------------------------------------------------------------------------
适配器设计模式
定义一个类事件的监听器接口
适配器简化了操作,定义监听器时候只要集成适配器,然后重写了需要的方法即可
适配器类必须是抽象的
适配器类重写方法,但是方法全部为空,但是实际上是你需要那个方法就重写哪个方法,起到了一个过渡的作用