多线程
1、JDK5对锁的升级
在学习生产者和消费者的时候在使用等待和唤醒机制的时候,发生了本方唤醒本方的。这样导致程序的效率降低。
在jdk5中对等待唤醒以及锁的机制进行了升级。
锁的升级:
在jdk5之前同步中获取锁和释放锁都是隐式的。把隐式的锁变成了显示由程序员自己手动的获取和释放。
jdk5对锁的描述:采用的接口来描述
在java.util.concurrent.locks包下有接口Lock它是专门放负责描述锁这个事物。
Lock锁代替了同步代码块。在多线程中能够使用同步代码块的地方都可以使用Lock接口来代替。
当我们使用Lock接口代替同步代码块的时候,就需要程序员手动的来获取锁和释放锁,如果在程序中出现了获取锁之后,没有释放锁,导致其他程序无法进入这个同步语句中。
需要使用try-finally语句在finally中书写释放锁的代码。
在Lock接口中lock方法和unLock方法分别是获取锁和释放锁。
//使用JDK5的锁完成售票的例子
import java.util.concurrent.locks.*;
class Ticket implements Runnable
{
int num = 100;
//创建锁对象
Lock loc = newReentrantLock(); //多态了
public void run()
{
while( true )
{
//获取锁
loc.lock();
try
{
if(num > 0 )
{
System.out.println(Thread.currentThread().getName()+"............."+num);
num--;
}
}
finally
{
//释放锁
loc.unlock();
}
}
}
}
class LockDemo
{
public static voidmain(String[] args)
{
//创建线程任务
Ticket t = new Ticket();
//创建线程对象
Thread tt = new Thread(t);
Thread tt2 = new Thread(t);
Thread tt3 = new Thread(t);
Thread tt4 = new Thread(t);
//开启线程
tt.start();
tt2.start();
tt3.start();
tt4.start();
}
}
2、JDK5对监视器方法的升级
JDK5对同步的锁进行了升级,同时还对等待唤醒机制也进行了升级。
在JDK5之前等待唤醒机制的方法和当前锁绑定在一起。在编写生产者和消费者任务的时候,由于消费者和生产者使用的同一个锁,那么就会导致使用当前这个锁来唤醒在这个锁上等待的线程的时,就可能发生生产者唤醒生产者或者消费者唤醒消费者。
到了JDK5之后,锁被Lock接口来描述,等待唤醒的方法也被重新封装成一个类。专门使用一个类负责等待唤醒。
JDK5中使用Condtion接口来专门负责描述等待唤醒机制。Condition代替了jdk5之前的Object类中的wait、notify、notifyAll方法。
Conditoin接口中的await方法代替了Object中wait方法。signal()
代替的notify signalAll代替notifyAll方法
当我们需要使用等待唤醒的时候,就需要获取到Condition对象,然后把这个Condition对象和Lock接口绑定在一起即可。这样就可以使用一个Lock下面绑定多个Condition
在Lock接口有个方法newCondition这个方法就可以让一个Condtion对象和Lock接口对象绑定在一起了。
4、多线程的细节
4.1、sleep和wait方法的异同
sleep和wait都可以让线程睡眠
不同:
sleep需要指定时间,而wait可以指定时间,也可以不用指定时间。
sleep时间到了线程就会重新恢复到运行状态。wait如果没有指定时间,必须通过notify、notifyAll方法来唤醒
sleep可以使用同步代码块中,也可以不使用同步代码块中,wait必须使用同步代码块中。
sleep睡眠后不会释放锁,而wait会释放锁。
4.2、停止线程和interrupt方法
一般情况下线程要结束,都是通过run方法运行完成,线程就结束了。如果要线程提前中止运行,可以使用stop方法。
但是stop方法过时了,原因有不安全因素。
stop方法中给出了相应的解决方案:在线程中可以定义一些变量或者标记,然后在线程运行的期间,判断这个变量或者标记,最终让线程执行的仍然运行完成。
如果线程长时间处于等待(冻结)状态可以使用interrupt方法来中断这种等待。
interrupt()
其实是把线程这种等待状态给清除,让线程重新恢复到运行状态。
4.3、守护线程、线程组、线程优先级
守护线程:后台线程。当我们直接创建的线程,没有设置它的任何属性时,这个线程一般都属于非守护线程(前台线程)。
非守护线程,它和主线程一起执行,当主线程执行完成之后,如果还有其他非守护线程没有执行结束,当前程序依然在正常的运行。
守护线程:它也是用来执行线程任务的,它会随着非守护线程一起执行。当程序中没有任何一个非守护线程在运行时,这时不管有多少个守护线程,它们及时没有执行完成,程序也会自动停止运行。守护线程就自定结束运行了。
线程组:
把完成类似功能的线程可以合并在一起,使用一个组来管理当前这些线程,可以通过组的方式来管理线程。
线程优先级:
线程优先级采用数字来标识,从1开始到10,一般情况下会使用1 5 10 来标记当前的线程的优先级
优先级高的线程执行的次数会比优先级低的线程多。优先级高,只能让cpu执行到这个线程的几率变高,而不是说cpu就一直在执行它。
getPriority()
获取当前线程的优先级
setPriority(int newPriority)
设置线程的优先级,newPriority参数可以是1-10
建议设置的时候1 5 10 这三个数字。
4.4、join和yield方法介绍
join()
让某个线程强制加入到当前cpu的执行队列中。在使用join加入其他线程到运行状态中来时,这个加入的语句肯定是写在其他的线程的执行代码中。书写加入线程的代码所在的那个线程此时就会处理临时冻结状态,等待被加入的线程执行结束。等被加入的线程执行结束了,它立刻回复运行的状态。
yield()
让当前正在执行的临时停顿一下,然后立刻就恢复运行状态。
多线程需要掌握的技术:
1、创建线程的2种方式 继承Thread和实现Runnable接口
2、掌握线程的安全问题发生的原因和解决
3、掌握单生产和单消费的原理以及等待唤醒机制
Eclipse使用
下载地址 www.eclipse.org
4、eclipse的快捷键
代码补全: alt + /
错误提示:ctrl + 1 如果在程序出现的小红x 这时可以按这个提示键,eclipse会给出响应的错误帮助
导包:ctrl + shift + o
快速得到方法的返回类型和变量名: ctrl + 2 + L
格式化代码:ctrl + shift + F
快速复制当前选中的代码: ctrl + alt + ↓
删除选中的代码: ctrl + D
移动选中的代码:alt+↑或者↓
添加或者删除单行注释:ctrl + /
添加多行注释: ctrl + shift + /
取消多行注释: ctrl + shift + \
String类介绍
String类到底是干什么:
学习Java中的常量的时候,我们学习一类常量叫字符串常量。字符串需要使用双引号引用起来。只要是使用双引号引用起来的数据都属于字符串。
在Java把所有的我们知道的存在的事物都可以使用类来描述。因此字符串也是java中存在一类数据,也属于一类,于是Java中使用String这个类来描述字符串这类数据。
Java这门语言,把所有的事物,或者是我们想象中的某些概念等信息都可以使用类、抽象类、接口等方式来描述。当使用这些类、抽象类、接口等把事物或者概念等信息描述完成之后,那么我们就按照对象的方式来操作这类事物。
1、String类介绍
String类位于java.lang包下。
Stirng在设计的时候是最终类,它不能再有子类。
api中对String描述:
String 类代表字符串。Java 程序中的所有字符串字面值(如"abc" )都作为此类的实例实现。
在程序只要使用了双引号引用起来的数据都属于字符串,都是String类的实例。
String s = “abc”; “abc”就是一个对象,它就能够调用方法。
字符串是常量;它们的值在创建之后不能更改。因为 String 对象是不可变的,所以可以共享。
当我们在程序书写了一个字符串,那么这个字符串就一直存在不能被改变。
“abc”
“abd”
此时在程序会有2个String的对象。分配是“abc”和“abd”
String是常量,可以共享:
String s = “abc”;
String s2 = “abc”;
这时在内存中仅有一个“abc”,s和s2这2个字符串引用指向了同一个对象。
字符串是常量,它还是对象,它存放在方法区的字符串常量池中。
2、String类中的构造方法
String类中有很多构造方法,可以把不同的数据变成一个String对象。
String() 创建一个字符串对象,其中没有任何字符数据
String(byte[] bytes)
把一个字节数组变成一个字符串对象
String(byte[] bytes, int offset, int length)
把一个字节数组中从offset位置开始共计把length个字节数据变成字符串对象
String(char[] value)
把一个字符数组变成字符串对象
String(char[] value, int offset, int count)
把字符数组中的字符从offset开始,共计把count个字符变成一个字符串对象
String(
String original)
把一个字符串变成一个新的字符串
3、String类中的方法:
String类是描述字符串,其中的方法都围绕操作字符串而设计的。
字符串的底层使用的数组。每个字符在字符串中都有自己的下标。
1、获得字符串字符的方法
char (int index)
charAt(int index)
就是根据指定的下标获取这个下标位置上的字符
2、获取字符串长度
int ( )
length()
返回当前字符串中字符的个数
3、反转字符串方法
木有 由于字符串是常量,反转就要改变字符串。
4、获取某个字符的下标
int (char ch)
indexOf(int ch)
字符串从前往后第一次出现的位置,如果指定的字符在字符串中没有返回-1
可以通过这个方法判断某个字符是否在字符串中存在。
indexOf(int ch, int fromIndex)
在字符串中从fromIndex位置开始查找当前ch第一次出现的位置。
indexOf(
String str)
获取指定的一个字符串在另外一个字符串中第一次出现的位置
5、比较两个字符串是否一样
6、添加新字符
7、获取某个字符在字符串中最后出现的位置
8、字符转成和十进制对应的数据
9、大小写转换
10、从原串中截取字符串
11、字符串各种判断
某个字符是否在字符串 某个字符串是否在指定的字符串 以什么开始 或者以什么结尾